didSelectItemAt causes UI to reflow/redraw every time value for lastSelectedIndex is changed, causing performance issue. I'm not sure if I have used @State properly to propagate value from child to parent.
P.S. I need to use UICollectionView for a reason instead of swiftui List or ScrollView.
P.S. I need to use UICollectionView for a reason instead of swiftui List or ScrollView.
Code Block import Foundation import SwiftUI struct ContentView: View { @State var lastSelectedIndex : Int = -1 var body: some View { ZStack { CustomCollectionView(lastSelectedIndex: $lastSelectedIndex) Text("Current Selected Index \(lastSelectedIndex)") } } } struct CustomCollectionView: UIViewRepresentable { @Binding var lastSelectedIndex : Int func makeUIView(context: Context) -> UICollectionView { let flowLayout = UICollectionViewFlowLayout() flowLayout.itemSize = CGSize(width: 400, height: 300) let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.reuseId) collectionView.delegate = context.coordinator collectionView.dataSource = context.coordinator collectionView.backgroundColor = .systemBackground collectionView.isDirectionalLockEnabled = true collectionView.backgroundColor = UIColor.black collectionView.showsVerticalScrollIndicator = false collectionView.showsHorizontalScrollIndicator = false collectionView.alwaysBounceVertical = false return collectionView } func updateUIView(_ uiView: UICollectionView, context: Context) { uiView.reloadData() } func makeCoordinator() -> CustomCoordinator { CustomCoordinator(self) } } class CustomCoordinator: NSObject, UICollectionViewDataSource, UICollectionViewDelegate { let parent:CustomCollectionView init(_ parent:CustomCollectionView) { self.parent = parent } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 100 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCollectionViewCell.reuseId, for: indexPath) as! CustomCollectionViewCell cell.backgroundColor = UIColor.red cell.label.text = "Current Index is \(indexPath.row)" NSLog("Called for Index \(indexPath.row)") return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { parent.lastSelectedIndex = indexPath.row } } class CustomCollectionViewCell: UICollectionViewCell { static let reuseId = "customCell" let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) label.numberOfLines = 0 contentView.addSubview(label) label.translatesAutoresizingMaskIntoConstraints = false label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
When you have a UIViewRepresentable, the method func updateUIView(_ uiView: UICollectionView, context: Context) is called every single time a @State/@Binding variable is changed. Currently your logic in that method is to call uiView.reloadData() every time. You could update the logic to only reload the data once, or only load it if certain conditions are met. For example:
Code Block swift struct CustomCollectionView: UIViewRepresentable { @Binding var lastSelectedIndex : Int private var didLoadData = false // ... func updateUIView(_ uiView: UICollectionView, context: Context) { if didLoadData { return } uiView.reloadData() didLoadData = true } // ... }