โœจ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)
    }
    
}

Last updated