【SwiftUI】LazyVGridを使って簡単なSF Symbolsのカタログアプリを作る
SwiftUIでUICollectionView
的な表現の仕方を学ぶついでに簡単なSF Symbolsのカタログアプリを作ってみることにしました。
はじめに
今回は縦方向にスクロール出来るUICollectionView
的な表現として、ScrollView
とLazyVGrid
を使っています。
作ったもの
環境
- Xcode 13.2.1
- iOS 15.0
- SFUserFriendlySymbols 0.2.2
SF Symbolsライブラリ
今回、SF Symbolsのライブラリとして自分で作ったユーザーに優しいSF Symbolsライブラリを使用します。
パッケージの追加
- Xcode上で
File
→Add Packages...
を押します。 - 開かれたページの右上にある検索窓に
https://github.com/littleossa/SFUserFriendlySymbols.git
を入力します。 -
SFUserFriendlySymbols
のパッケージが現れたら、Add Package
ボタンを押します。 - 完了すると、packageが追加されます
Grid内で使用するViewを作成する
CatalogItem
import SwiftUI import SFUserFriendlySymbols struct CatalogItem: View { private let symbol: SFSymbols private let color: Color private let backgroundColor: Color private let baseLength: CGFloat private let imageWidth: CGFloat init(symbol: SFSymbols, color: Color, backgroundColor: Color) { self.symbol = symbol self.color = color self.backgroundColor = backgroundColor baseLength = UIScreen.main.bounds.width * 0.25 imageWidth = baseLength * 0.5 } var body: some View { VStack(alignment: .center) { ZStack { RoundedRectangle(cornerRadius: 16) .foregroundColor(backgroundColor) RoundedRectangle(cornerRadius: 16) .stroke(.gray, lineWidth: 0.5) Image(symbol: symbol) .resizable() .scaledToFit() .frame(width: imageWidth) .foregroundColor(color) } .frame(width: baseLength, height: baseLength) HStack { Spacer() Text(symbol.rawValue) .frame(height: 35, alignment: .top) .multilineTextAlignment(.center) .font(.caption) Spacer() } } } }
プレビュー
シンボルイメージ部分
ZStack { // 背景 RoundedRectangle(cornerRadius: 16) .foregroundColor(backgroundColor) // 枠線 RoundedRectangle(cornerRadius: 16) .stroke(.gray, lineWidth: 0.5) // シンボルイメージ Image(symbol: symbol) .resizable() .scaledToFit() .frame(width: imageWidth) .foregroundColor(color) } .frame(width: baseLength, height: baseLength)
今回はUIScreen.main.bounds.width * 0.25
したものを基準の長さにしており、imageWidth
はその基準の長さの半分の値にしています。
baseLength = UIScreen.main.bounds.width * 0.25 imageWidth = baseLength * 0.5
シンボルネーム部分
HStack { Spacer() Text(symbol.rawValue) .frame(height: 35, alignment: .top) .multilineTextAlignment(.center) .font(.caption) Spacer()
シンボルネームが中心にきて、尚且つサイドにスペースが出来て欲しかったのでHStack
内でText
を記述して両サイドにSpacer()
を配置しています。
LazyVGridを使用して縦方向にGridを組む
LazyVGridとは
子ビューを垂直方向に拡大するグリッドに配置し、必要な場合にのみアイテムを作成するコンテナビュー
引用: LazyVGrid
このLazyとは、グリッドビューが必要になるまで生成されないことを意味しています。
CatalogView
import SwiftUI import SFUserFriendlySymbols struct SymbolsCatalogView: View { @State private var selectedColor = Color.black @State private var backgroundColor = Color.white var body: some View { let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3) ScrollView { LazyVGrid(columns: columns) { ForEach(SFSymbols.allCases, id: \.self) { CatalogItem(symbol: $0, color: selectedColor, backgroundColor: backgroundColor) } } .padding(.top) .padding(.horizontal) } .toolbar { ToolbarItem(placement: .bottomBar) { ColorPicker("背景", selection: $backgroundColor) } ToolbarItem(placement: .bottomBar) { ColorPicker("カラー", selection: $selectedColor) } } } }
プレビュー
グリッド部分
let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3) ScrollView { LazyVGrid(columns: columns) { ForEach(SFSymbols.allCases, id: \.self) { CatalogItem(symbol: $0, color: selectedColor, backgroundColor: backgroundColor) } } .padding(.top) .padding(.horizontal) }
GridItem
LazyGrid
を使用する為には、GridItem
が必要です。
let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3)
repeating
には、GridItem.Size
を設定します。今回は特に固定させないので.flexible
に対応するようにしました。
count
には、今回は垂直方向のグリッドなので、水平方向のアイテムの個数になります。
LazyVGrid
ScrollView { LazyVGrid(columns: columns) { ForEach(SFSymbols.allCases, id: \.self) { CatalogItem(symbol: $0, color: selectedColor, backgroundColor: backgroundColor) } } }
ScrollView
が必要な理由は、LazyVGrid
だけを記述すると、スクロールすることが出来ず、グリッド内のアイテムが画面以上ある場合は生成することが出来なくなってしまうからです。
あとは、LazyVGrid
内でForEach
を使って、SFSymbols.allCases
を呼んであげてCatalogItem
を生成します。
ちなみにSFUserFriendlySymbols
のallCases
は、使用しているOS
で使用可能な全てのシンボルを返してくれます。
おまけ ToolBar
ここまででSF Symbolsをカタログ風に表現することが出来たのですが、せっかくなので色を変更出来る様にツールバーを作成してみました。
.toolbar { ToolbarItem(placement: .bottomBar) { ColorPicker("背景", selection: $backgroundColor) } ToolbarItem(placement: .bottomBar) { ColorPicker("カラー", selection: $selectedColor) } }
背景色を設定できるColorPicker
とシンボルの色を設定できるColorPicker
を画面下部のバーに設置しました。
これで簡易なSF Symbolsのカタログの完成です。
おわりに
UICollectionView
だと使用するまでに色々と記述しないといけなかったですが、少ないコードで同じような表現が出来る様になった気がしました。
LazyVStack
を学ぶという趣旨で最初は進めたのですが、カタログを作る行為が途中から楽しくなってしまいました、、
今回は単色しか色を設定出来ない仕様なので、階層カラーやパレットカラー、マルチカラーにも対応していきたいと思います。またカテゴリーや名前で検索できるようになると更に良さそうですね。
SF Symbolsに幸あれ