✨Grid
⬆️ 需要: GridLayout, arr.index(of:), .if(_:then:)
/*
* ⭐️ Required:
* - 🌀View + if
* - 🌀Array + index
* - 📦 GridLayout
*/
import SwiftUI
// 🌅 Grid
public struct Grid<Item: Identifiable, ItemView: View>: View {
let items : [Item] // items to arrange
let viewForItem : (Item) -> ItemView // turn item into some View
let cellAspectRatio: CGFloat // desired cell aspect ratio
let showCellBorder : Bool // show cell border or not
// Grid(items){ item in ... }
public init(
_ items: [Item],
cellAspectRatio: CGFloat = 1, // ⭐️ default: aspect ratio = 1
showCellBorder : Bool = false, // ⭐️ default: don't show cell border
viewForItem : @escaping (Item) -> ItemView
) {
self.items = items
self.viewForItem = viewForItem
self.cellAspectRatio = cellAspectRatio
self.showCellBorder = showCellBorder
}
public var body: some View {
// ⭐️ GeometryReader
GeometryReader { geo in self.itemViews(in: geo.size) }
}
// helper functions
func itemViews(in size: CGSize) -> some View {
let n = items.count
// ⭐️ prepare best layout for items (require: 📦 GridLayout)
let layout = GridLayout(itemCount: n, in: size, nearAspectRatio: cellAspectRatio)
// ⭐️ ForEach
return ForEach(items) { item in self.view(for: item, in: layout) }
}
func view(for item: Item, in layout: GridLayout) -> some View {
let index = items.index(of: item)! // 🌀Array + index
let center = layout.centerOfCell(at: index) // 📦 GridLayout
return viewForItem(item)
// ⭐️ best layout cell size
.frame(layout.cellSize)
// show cell border or not
.if(showCellBorder) { $0.border(Color.black) } // 🌀View + if
// ⚠️ 注意:
// 一旦加上 .position 之後,.frame 會變成整個
// GeometryReader 的大小,不再是單一卡片的大小。
// ⭐️ put item view at the right position
.position(center)
}
}
GridLayout - help calculate best layout.
stack - SwiftUI views for 1D layout.
Grids - SwiftUI views for 2D layout.
used in Emoji Memory Game 📚
.grids() - draw grid lines in the background.
MyGrid 改編自這裡。
Last updated