UICollectionView and SwiftUI?

后端 未结 16 1439
时光说笑
时光说笑 2020-12-02 07:32

How to create grid of square items (for example like in iOS Photo Library) with SwiftUI?

I tried this approach but it doesn\'t work:

var body: some          


        
相关标签:
16条回答
  • 2020-12-02 07:50

    Since I'm not using Catalina Beta, I wrote here my code you can run on Xcode 11 (Mojave) as a playground to take advantage of run-time compile and Preview

    Basically when u look for a grid approach u should take in mind that SwiftUI child View get ideal size parameter from parent view so they can auto-adapt based on their own content, this behavior can be overridden (do not confuse with swift Override directive) by forcing view to a specific size via .frame(...) method.

    In my opinion this make View behavior stable as well as the Apple SwiftUI framework has been correctly tested.

    import PlaygroundSupport
    import SwiftUI
    
    struct ContentView: View {
    
        var body: some View {
    
            VStack {
                ForEach(0..<5) { _ in
                    HStack(spacing: 0) {
                        ForEach(0..<5) { _ in
                            Button(action: {}) {
                                Text("Ok")
                            }
                            .frame(minWidth: nil, idealWidth: nil, maxWidth: .infinity, minHeight: nil, idealHeight: nil, maxHeight: .infinity, alignment: .center)
                            .border(Color.red)
                        }
                    }
                }
            }
        }
    }
    
    let contentView = ContentView()
    PlaygroundPage.current.liveView = UIHostingController(rootView: contentView)
    
    0 讨论(0)
  • 2020-12-02 07:51

    iOS 14 and XCode 12

    SwiftUI for iOS 14 brings a new and nativ grid view that is easy to use, its called LazyVGrid: https://developer.apple.com/documentation/swiftui/lazyvgrid

    You can start with defining an array of GridItem's. GridItems are used to specify layout properties for each column. In this case all GridItems are flexible.

    LazyVGrid takes an array of GridItem's as its parameter and displays the containing views according to the defined GridItems.

    import SwiftUI
    
    struct ContentView: View {
        
        let columns = [
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible())
        ]
        
        var body: some View {
            ScrollView {
                LazyVGrid(columns: columns) {
                    ForEach(0...100, id: \.self) { _ in
                        Color.orange.frame(width: 100, height: 100)
                    }
                }
            }
        }
    }
    

    0 讨论(0)
  • 2020-12-02 07:53

    I’ve written a small component called

    0 讨论(0)
  • 2020-12-02 07:56

    XCode 11.0

    After looking for a while I decided that I wanted all the convenience and performance form the UICollectionView. So I implemented the UIViewRepresentable protocol.

    This example does not implement the DataSource and has a dummy data: [Int] field on the collection view. You would use a @Bindable var data: [YourData] on the AlbumGridView to automatically reload your view when the data changes.

    AlbumGridView can then be used like any other view inside SwiftUI.

    Code

    class AlbumPrivateCell: UICollectionViewCell {
        private static let reuseId = "AlbumPrivateCell"
    
        static func registerWithCollectionView(collectionView: UICollectionView) {
            collectionView.register(AlbumPrivateCell.self, forCellWithReuseIdentifier: reuseId)
        }
    
        static func getReusedCellFrom(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> AlbumPrivateCell{
            return collectionView.dequeueReusableCell(withReuseIdentifier: reuseId, for: indexPath) as! AlbumPrivateCell
        }
    
        var albumView: UILabel = {
            let label = UILabel()
            return label
        }()
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            contentView.addSubview(self.albumView)
    
            albumView.translatesAutoresizingMaskIntoConstraints = false
    
            albumView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
            albumView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
            albumView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
            albumView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        }
    
        required init?(coder: NSCoder) {
            fatalError("init?(coder: NSCoder) has not been implemented")
        }
    }
    
    struct AlbumGridView: UIViewRepresentable {
        var data = [1,2,3,4,5,6,7,8,9]
    
        func makeUIView(context: Context) -> UICollectionView {
            let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
            collectionView.backgroundColor = .blue
            collectionView.translatesAutoresizingMaskIntoConstraints = false
            collectionView.dataSource = context.coordinator
            collectionView.delegate = context.coordinator
    
            AlbumPrivateCell.registerWithCollectionView(collectionView: collectionView)
            return collectionView
        }
    
        func updateUIView(_ uiView: UICollectionView, context: Context) {
            //
        }
    
        func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }
    
        class Coordinator: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
            private let parent: AlbumGridView
    
            init(_ albumGridView: AlbumGridView) {
                self.parent = albumGridView
            }
    
            // MARK: UICollectionViewDataSource
    
            func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                self.parent.data.count
            }
    
            func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                let albumCell = AlbumPrivateCell.getReusedCellFrom(collectionView: collectionView, cellForItemAt: indexPath)
                albumCell.backgroundColor = .red
    
                return albumCell
            }
    
            // MARK: UICollectionViewDelegateFlowLayout
    
            func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
                let width = collectionView.frame.width / 3
                return CGSize(width: width, height: width)
            }
        }
    }
    

    Screenshot

    0 讨论(0)
  • 2020-12-02 08:01

    Try using a VStack and HStack

    var body: some View {
        GeometryReader { geometry in
            VStack {
                ForEach(1...3) {_ in
                    HStack {
                        Color.orange.frame(width: 100, height: 100)
                        Color.orange.frame(width: 100, height: 100)
                        Color.orange.frame(width: 100, height: 100)
                    }.frame(width: geometry.size.width, height: 100)
                }
            }
        }
    }
    

    You can wrap in a ScrollView if you want scrolling

    0 讨论(0)
  • 2020-12-02 08:02

    Although the next WWDC is right around the corner, we're still missing a collection view in SwiftUI. I have tried to provide a decent example on how to create your own SwiftUI collection view using UIViewControllerRepresentable and Combine. I opted for creating my own collection view instead of using open source libraries as either I felt they were missing some key features or were bloated with too many things. In my example, I have used UICollectionViewDiffableDataSource and UICollectionViewCompositionalLayout to create the collection view. It supports both pullToRefresh and pagination functionality.

    The full implementation can be found in: https://github.com/shabib87/SwiftUICollectionView.

    0 讨论(0)
提交回复
热议问题