Make blazing fast lists and collection views

RSS for tag

Discuss the WWDC21 session Make blazing fast lists and collection views.

Posts under wwdc21-10252 tag

15 Posts

Post

Replies

Boosts

Views

Activity

Is there a way to update supplementary view efficiently, analogy to update items efficiently using reconfigureItems?
In iOS15, we have an efficient way to update items cell, by using reconfigureItems. Here's the code snippet to perform such efficient update. Update items cell efficiently using reconfigureItems private func reconfigureRecordingRow(_ recording: Recording) { var snapshot = dataSource.snapshot() snapshot.reconfigureItems([recording]) dataSource.apply(snapshot) } private func makeDataSource() -> DataSource { let dataSource = DataSource( collectionView: collectionView, cellProvider: { [weak self] (collectionView, indexPath, anyHashable) -> UICollectionViewCell? in guard let self = self else { return nil } guard let recordingCell = collectionView.dequeueReusableCell( withReuseIdentifier: "recording", for: indexPath) as? RecordingCell else { return nil } When reconfigureRecordingRow is called, cellProvider's function will be executed. collectionView.dequeueReusableCell is able to re-use existing UICollectionViewCell, without constructing new UICollectionViewCell However, I was wondering, how can I achieve a similar efficiency, if I have a section, with header supplementary view, and without any item? For instance Not able to update supplementary view efficiently private func reloadAttachmentRow() { var snapshot = dataSource.snapshot() let sectionIdentifiers = snapshot.sectionIdentifiers if sectionIdentifiers.contains(.attachment) { snapshot.reloadSections([.attachment]) } else { snapshot.insertSections([.attachment], beforeSection: .title) } dataSource.apply(snapshot) } dataSource.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in guard let self = self else { return nil } if kind == UICollectionView.elementKindSectionHeader { let section = indexPath.section let sectionIdentifier = self.sectionIdentifier(section) switch sectionIdentifier { case .attachment: guard let collageViewHeader = collectionView.dequeueReusableSupplementaryView( ofKind: kind, withReuseIdentifier: "attachment", for: indexPath) as? CollageViewHeader else { return nil } When reloadSections is called, dataSource.supplementaryViewProvider will be executed. As per my testing, collectionView.dequeueReusableSupplementaryView will return a new instance of UICollectionReusableView each time. As a result, I can visually observe the entire section is "flickering", when reloadAttachmentRow is called. I was wondering, how can we update supplementary view efficiently?
0
0
954
May ’22
iPhone13 CollectionView issue
When I use UICollectionView on iPhone13 and the latest devices, [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES] will cause caton. animated:YES has no animation effect, but this method works well on other devices, They are IOS 15.0.2 systems - (void)topClick:(UIButton *)sender{         if (sender.selected) {         return;     }          NSArray *array = [NSArray array];     if (sender == self.topLuck) {         array = self.luckList;     } else if (sender == self.topLuxurious){         array = self.luxuriousList;     } else if (sender == self.topVip){         array = self.vipList;     } else if (sender == self.topPk){         array = self.pkList;     } else if (sender == self.packetBtn){         array = self.packetList;     }     NSInteger section = [self.datas indexOfObject:array]; //    [self didScrollToSection:section];          if (section < self.datas.count) {         [self.giftCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];     } } - (UICollectionView *)giftCollectionView{     if (!_giftCollectionView) {         LiveGiftPickerLayout *layout = [LiveGiftPickerLayout new];         layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;         layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);         CGFloat width = floor((kScreen_Width - 20)/4);         layout.itemSize = CGSizeMake(width, width);         layout.minimumLineSpacing = 0;         layout.minimumInteritemSpacing = 0;         _giftCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];         _giftCollectionView.dataSource = self;         _giftCollectionView.delegate = self;         _giftCollectionView.backgroundColor = [UIColor clearColor];         _giftCollectionView.showsHorizontalScrollIndicator = NO;         _giftCollectionView.pagingEnabled = YES;         [_giftCollectionView registerClass:[GiftPickerCollectionViewCell class] forCellWithReuseIdentifier:[GiftPickerCollectionViewCell currentIdentifier]];     }     return _giftCollectionView; }
3
0
1.2k
Apr ’22
How to display list of items (grouped alphabetically) using UICollectionView List API?
I'm trying to display a list of songs using UICollectionView's List API. I would also like them grouped by the first letter of the song. At first, I thought I'd have something like this: let sections = [ LibrarySection(name: A, songs: [ Song(name: "A Song"), Song(name: "Another Song"), ]), LibrarySection(name: B, songs: [ Song(name: "B Song"), Song(name: "B another Song"), ]), ] var snapshot = NSDiffableDataSourceSnapshot<LibrarySection, LibraryRow>() snapshot.appendSections(sections) sections.forEach { section in snapshot.appendItems(section.songs, toSection: section) } dataSource.apply(snapshot, animatingDifferences: true) But I facepalmed when I realized the smart thing to do is this: let items = [ Song(name: "A Song"), Song(name: "Another Song"), Song(name: "B Song"), Song(name: "B another Song") ] The question I have is, what would the snapshot logic look like such that I am minimizing the amount of times I have to instantiate items and sections? var snapshot = NSDiffableDataSourceSnapshot<LibrarySection, LibraryRow>() ??? dataSource.apply(snapshot, animatingDifferences: true) Thanks for any feedback you may have!!!
0
0
1.1k
Mar ’22
UICollectionViewCompositionalLayout
Hello, how should I perform two next two operations with UICompositionalLayout? Scroll To Specific offset Change layout of the item, I'm scrolling to. Whenever I try to call collectionView.collectionViewLayout.invalidateLayout(), I get reset: Content Offset of UICollectionView The layout change of the item is not updated Here is the example of the layout I try to use.    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                           heightDimension: .estimated(100))     let item = NSCollectionLayoutItem(layoutSize: itemSize)     item.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: nil, top: .fixed(8), trailing: nil, bottom: .fixed(8))     let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                            heightDimension: .estimated(100))     let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])     let section = NSCollectionLayoutSection(group: group)     return section And here is the example of cell class ReelTextCellView: UICollectionViewCell {   private var textView: UITextView!   private var infoHolderView: UIView!   private var copyButton: UIButton!   private var scrollView: UIScrollView!   private var heightConstraint: NSLayoutConstraint!   var isExpanded = false   override init(frame: CGRect) {     super.init(frame: .zero)     buildView()   }   required init?(coder: NSCoder) {     fatalError("init(coder:) has not been implemented")   }   override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {     let attributes = super.preferredLayoutAttributesFitting(layoutAttributes)     attributes.frame.size = .init(width: contentView.frame.width, height: isExpanded ? 300 : 100)     return attributes   } // Called with the cellWillAppear and manually for indexPathsForVisibleItems   func update(with appeareance: Appearance) {     isExpanded = appeareance.isExpanded     ///    heightConstraint.constant = appeareance.isExpanded ? 300 : 100   } private extension ReelTextCellView {   func buildView() {     infoHolderView = UIView()     contentView.addSubview(infoHolderView) {       contentView.bottomAnchor.constraint(equalTo: infoHolderView.bottomAnchor)       contentView.leadingAnchor.constraint(equalTo: infoHolderView.leadingAnchor)       contentView.trailingAnchor.constraint(equalTo: infoHolderView.trailingAnchor)       infoHolderView.heightAnchor.constraint(equalToConstant: 30)     }     let separatorView = UIView()     separatorView.backgroundColor = Assets.Colors.separator.color     infoHolderView.addSubview(separatorView) {       separatorView.topAnchor.constraint(equalTo: infoHolderView.topAnchor)       separatorView.leadingAnchor.constraint(equalTo: infoHolderView.leadingAnchor)       separatorView.trailingAnchor.constraint(equalTo: infoHolderView.trailingAnchor)       separatorView.heightAnchor.constraint(equalToConstant: 0.5)     }     textView = UITextView()     contentView.addSubview(textView) {       textView.topAnchor.constraint(equalTo: contentView.topAnchor)       textView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)       textView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)       textView.bottomAnchor.constraint(equalTo: infoHolderView.topAnchor)     }   } }
0
0
1.6k
Feb ’22
[once issue]there is large gap between collectionview contents and navigation controller
I have a collection view with custom layout. and it has different kinds of dynamic contents. suddenly when i tap on an item, go to next viewController and move back to collection view, there is a large gap between navigation controller and collection view content. could someone please share how to resolve this issue or how to find out the cause? please note that, collection view resides in a pageview controller
0
0
730
Feb ’22
ListView with personal data
I will briefly explain my view. My goal is to make a list where you can enter all personal information like a kind of emergency passport. There should also be text fields where you can tap on the plus button and then there is a new text field. On the top right I want to make an edit button that you can delete text fields again. I will connect this view with another SwiftUI view file. Does anyone have an idea how to solve this problem with the list? import SwiftUI struct ListeDaten: Identifiable { let id = UUID() let Name: String let Adresse: String var Telefonnummern: [String] = [] var Something: String = "" } struct ListeDaten: View {     var body: some View {                  TextField(Name: "Name/Vorname")         TextField(Adresse: "Adresse")         ForEach(id: \.self) {Telefonnummern in TextField("Telefonnummer")}         Button(action: {             Telefonnummern.append("")         })         {             Image(systemName: "plus.circle.fill")                 .foregroundColor(Color(.systemGreen))         }     } } struct ListeDaten_Previews: PreviewProvider {     static var previews: some View {         ListeDaten()     } }
0
0
706
Jan ’22
EPG data in a collectionview
I spoke to an Apple Engineer at WWDC 2021 about how to implement an EPG (Electronic Program Guide, see image below) in a collectionView. I was recommended to use a UICollectionViewCompositionalLayout where each program corresponds to an Item and each channel corresponds to a Section (the section being provided by a SectionProvider). Furthermore, I was told to override preferredLayoutAttributesFitting to set the size of each cell. However, I have two difficult issues that I have not been able to come around: I cannot figure out how to ensure the CollectionView displays all cells correctly at the right spot, such that the time is aligned vertically for all channels. I am using NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .estimated(estimatedWidth), heightDimension: .fractionalHeight(1))), which provides an estimated width, but this estimated width is apparently used for all cells not in the view, causing the cells to be rendered at the wrong spot as soon as I scroll to the right. The performance when scrolling is terrible, probably due to my overriding of preferredLayoutAttributesFitting on the cell, which causes the cell to change its width. I was instructed not to use "self sizing cells" as this would cause performance problems. But I cannot figure a way out of this. How do I tell the CollectionView how to render the cells at the proper spot and at the same time avoid "self sizing cells"? Any help would be highly appreciated!
0
0
1.3k
Jan ’22
UICollectionView with DiffableDataSource
Xcode 13.1, iOS 25 SDK I have a UICollectionView (with a custom UICollectionViewLayout) which I am updating with a DiffableDataSource. This CollectionView displays a particular data object (with a given number of sections and items). The user can choose to display a different object (with a different number of sections and items), reusing this CollectionView. When this occurs, I do the following: (pass the new data object to the custom layout) let layout = collectionView.collectionViewLayout layout.invalidateLayout() collectionView.contentSize = layout.collectionViewContentSize (calculate a new snapshot and apply it) When the new data object has FEWER sections and/or items as the first, I get a series of warning messages (one for each of the cells that are no longer in the collection view) as follows: 2021-12-07 14:29:02.239301-0600 WineCorner[82916:1921357] [CollectionView] Layout attributes <UICollectionViewLayoutAttributes: 0x7f77b3047e00> index path: (<NSIndexPath: 0xa0f0b1eb018e754a> {length = 2, path = 0 - 4}); frame = (578.118 6; 160 160); transform = [0.70710678118654757, -0.70710678118654746, 0.70710678118654746, 0.70710678118654757, 0, 0]; zIndex = 1; were received from the layout <WineCorner.WineRackLayout: 0x7f77b1f1a0c0> but are not valid for the data source counts. Attributes will be ignored. Obviously, I am not handling the situation correctly. What should I do so that these warning messages are not issued?
0
0
1.2k
Dec ’21
UICollectionView raises an exception when setting `layoutAttributesForElements` on iOS 15
Assertion failure in -[UICollectionView _setNeedsVisibleCellsUpdate:withLayoutAttributes:], UICollectionView.m:1511  I have the following structure here -| UITableView -| UITableViewCell   -| UICollectionView           -| UICollectionViewCell           -| UICollectionViewCell ... when I override func systemLayoutSizeFitting in TableViewCell, The crashed occurred.
0
0
801
Nov ’21
tvOS 15 - Cell registration inside a diffable data source cell provider exception
What follows is about tvOS 15 but may also apply to iOS 15. Our app may display several types of UICollectionView cells and it depends on the content sent by our backend. Prior to tvOS 15, we used to lazily instantiate UICollectionView cell registrations when needed for the first time while building a UICollectionViewDiffableDataSource. Eventually, each cell registration is only instantiated once (or never). Now tvOS 15 throws an exception when doing so, pretending to prevent the app from creating a new cell registration each time. And it does not care whether it's actually a new cell registration each time or one that is lazily instantiated once. Here is the exception: *** Assertion failure in -[UICollectionView dequeueConfiguredReusableCellWithRegistration:forIndexPath:item:], UICollectionView.m:7413 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to dequeue a cell using a registration that was created inside -collectionView:cellForItemAtIndexPath: or inside a UICollectionViewDiffableDataSource cell provider. Creating a new registration each time a cell is requested will prevent reuse and cause created cells to remain inaccessible in memory for the lifetime of the collection view. Registrations should be created up front and reused. Registration: <UICollectionViewCellRegistration: 0x6000000f8c60>' I understand the concern but lazy instantiation is a thing and it should not be for forbidden for the sake of best practices that are not related to it. In my humble opinion, this assert should be removed and apps should be allowed to create cell registrations on the fly.
3
0
2.1k
Sep ’21
SwiftUI List section spacing
How to remove the spacing between List plain style section in swiftui iOS 15 struct ContentView: View {   var body: some View {     List {       Section {         Text("Hello, World!")         Text("Hello, World!")         Text("Hello, World!")       }       Section {         Text("Hello, World!")       }       Section {         Text("Hello, World!")         Text("Hello, World!")       } header: {         Text("section")       }     }.listStyle(.plain)   } }
1
0
8.3k
Sep ’21
App crashing while using collection view
I was trying to have a secondary collection view with circle images above (y axis) the functioning collection view but its crashing and throwing this error Error code: could not dequeue a view of kind: UICollectionElementKindCell with identifier CircleCollectionViewCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard ViewController code: // //  ViewController.swift //  Main_app // //  Created by Kushagr Agarwal on 23/08/21. // import UIKit class ViewController: UIViewController {     @IBOutlet var collectionView: UICollectionView!          @IBOutlet var topCollectionView: UICollectionView!          @IBOutlet weak var Leading: NSLayoutConstraint!          @IBOutlet weak var Trailing: NSLayoutConstraint!          @IBOutlet private weak var Menubutton: UIButton!     var menuOut = false               override func viewDidLoad() {         super.viewDidLoad()         // Do any additional setup after loading the view.         //self.navigationItem.titleView = UIImageView(image: UIImage(named: "Logo"))                  collectionView.register(MiddleCollectionViewCell.nib(), forCellWithReuseIdentifier: MiddleCollectionViewCell.identifier)                  collectionView.delegate=self         collectionView.dataSource=self                  topCollectionView.register(CircleCollectionViewCell.self, forCellWithReuseIdentifier: CircleCollectionViewCell.identifier)         topCollectionView.delegate=self         topCollectionView.dataSource=self //       Menu //       start                  let destructiveAction = UIAction(title: "Delete",image: UIImage(systemName: "nosign") , attributes: .destructive) { (_) in             print("Delete")         }                  let menu = UIMenu(title: "", children: [             UIAction (title: "Add New", image: UIImage(systemName: "plus.circle"), handler: { _ in  }),             UIAction (title: "Manage", image: UIImage(systemName: "hammer"), handler: { _ in  }),             destructiveAction         ])         self.Menubutton.menu = menu //    Menu end     } // Menu animation     @IBAction func MenuTap(_ sender: Any) {         if menuOut == false {             Leading.constant = -150             Trailing.constant = 150             menuOut = true         }         else{             Leading.constant = 0             Trailing.constant = 0             menuOut = false         }         UIView.animate(withDuration: 0.2, delay: 0.0 , options: .curveEaseIn,animations: {             self.view.layoutIfNeeded()         }){(animationComplete) in             print("Animation Completed")         }     } // Menu animation ends } // used for upper collection view extension ViewController: UICollectionViewDelegate {          func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {         collectionView.deselectItem(at: indexPath, animated: true )         print("btn tapped")              }           } extension ViewController: UICollectionViewDataSource {     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {         return 12     }     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MiddleCollectionViewCell.identifier, for: indexPath) as! MiddleCollectionViewCell         let topcell = collectionView.dequeueReusableCell(withReuseIdentifier: CircleCollectionViewCell.identifier, for: indexPath) as! CircleCollectionViewCell         topcell.configure(with: "")                  cell.configure(with: UIImage(named: "four")!)         return cell; topcell     } } //extension ViewController: UICollectionViewDelegateFlowLayout { // //}
1
0
2.1k
Sep ’21
Applying new snapshot to diffable data source in iOS 15 trigger unnecessary cell registration call
I try to figure out the improvement of apply(_:animatingDifferences:) function call without animation in iOS 15 Simulator. As log shown below, after removing an item and apply edited snapshot to diffable data source, it trigger several unnecessary calling to new cell that did not appear on screen. ENV: MacBook Air (M1, 2020), macOS Big Sur 11.4 (20F71) Xcode Version 13.0 beta (13A5154h), iOS 15.0 Simulator configure AlbumItemCell:(0x0000000128042400) at section:(0), item:(0) configure AlbumItemCell:(0x0000000125624aa0) at section:(0), item:(1) configure AlbumItemCell:(0x00000001280442a0) at section:(0), item:(2) configure AlbumItemCell:(0x0000000128045670) at section:(0), item:(3) configure AlbumItemCell:(0x0000000128050af0) at section:(0), item:(4) configure AlbumItemCell:(0x0000000125626430) at section:(0), item:(5) remove last items configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(0) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(1) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(2) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(3) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(4)
6
0
5.9k
Jun ’21
Is there a way to update supplementary view efficiently, analogy to update items efficiently using reconfigureItems?
In iOS15, we have an efficient way to update items cell, by using reconfigureItems. Here's the code snippet to perform such efficient update. Update items cell efficiently using reconfigureItems private func reconfigureRecordingRow(_ recording: Recording) { var snapshot = dataSource.snapshot() snapshot.reconfigureItems([recording]) dataSource.apply(snapshot) } private func makeDataSource() -> DataSource { let dataSource = DataSource( collectionView: collectionView, cellProvider: { [weak self] (collectionView, indexPath, anyHashable) -> UICollectionViewCell? in guard let self = self else { return nil } guard let recordingCell = collectionView.dequeueReusableCell( withReuseIdentifier: "recording", for: indexPath) as? RecordingCell else { return nil } When reconfigureRecordingRow is called, cellProvider's function will be executed. collectionView.dequeueReusableCell is able to re-use existing UICollectionViewCell, without constructing new UICollectionViewCell However, I was wondering, how can I achieve a similar efficiency, if I have a section, with header supplementary view, and without any item? For instance Not able to update supplementary view efficiently private func reloadAttachmentRow() { var snapshot = dataSource.snapshot() let sectionIdentifiers = snapshot.sectionIdentifiers if sectionIdentifiers.contains(.attachment) { snapshot.reloadSections([.attachment]) } else { snapshot.insertSections([.attachment], beforeSection: .title) } dataSource.apply(snapshot) } dataSource.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in guard let self = self else { return nil } if kind == UICollectionView.elementKindSectionHeader { let section = indexPath.section let sectionIdentifier = self.sectionIdentifier(section) switch sectionIdentifier { case .attachment: guard let collageViewHeader = collectionView.dequeueReusableSupplementaryView( ofKind: kind, withReuseIdentifier: "attachment", for: indexPath) as? CollageViewHeader else { return nil } When reloadSections is called, dataSource.supplementaryViewProvider will be executed. As per my testing, collectionView.dequeueReusableSupplementaryView will return a new instance of UICollectionReusableView each time. As a result, I can visually observe the entire section is "flickering", when reloadAttachmentRow is called. I was wondering, how can we update supplementary view efficiently?
Replies
0
Boosts
0
Views
954
Activity
May ’22
iPhone13 CollectionView issue
When I use UICollectionView on iPhone13 and the latest devices, [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES] will cause caton. animated:YES has no animation effect, but this method works well on other devices, They are IOS 15.0.2 systems - (void)topClick:(UIButton *)sender{         if (sender.selected) {         return;     }          NSArray *array = [NSArray array];     if (sender == self.topLuck) {         array = self.luckList;     } else if (sender == self.topLuxurious){         array = self.luxuriousList;     } else if (sender == self.topVip){         array = self.vipList;     } else if (sender == self.topPk){         array = self.pkList;     } else if (sender == self.packetBtn){         array = self.packetList;     }     NSInteger section = [self.datas indexOfObject:array]; //    [self didScrollToSection:section];          if (section < self.datas.count) {         [self.giftCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];     } } - (UICollectionView *)giftCollectionView{     if (!_giftCollectionView) {         LiveGiftPickerLayout *layout = [LiveGiftPickerLayout new];         layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;         layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);         CGFloat width = floor((kScreen_Width - 20)/4);         layout.itemSize = CGSizeMake(width, width);         layout.minimumLineSpacing = 0;         layout.minimumInteritemSpacing = 0;         _giftCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];         _giftCollectionView.dataSource = self;         _giftCollectionView.delegate = self;         _giftCollectionView.backgroundColor = [UIColor clearColor];         _giftCollectionView.showsHorizontalScrollIndicator = NO;         _giftCollectionView.pagingEnabled = YES;         [_giftCollectionView registerClass:[GiftPickerCollectionViewCell class] forCellWithReuseIdentifier:[GiftPickerCollectionViewCell currentIdentifier]];     }     return _giftCollectionView; }
Replies
3
Boosts
0
Views
1.2k
Activity
Apr ’22
How to display list of items (grouped alphabetically) using UICollectionView List API?
I'm trying to display a list of songs using UICollectionView's List API. I would also like them grouped by the first letter of the song. At first, I thought I'd have something like this: let sections = [ LibrarySection(name: A, songs: [ Song(name: "A Song"), Song(name: "Another Song"), ]), LibrarySection(name: B, songs: [ Song(name: "B Song"), Song(name: "B another Song"), ]), ] var snapshot = NSDiffableDataSourceSnapshot<LibrarySection, LibraryRow>() snapshot.appendSections(sections) sections.forEach { section in snapshot.appendItems(section.songs, toSection: section) } dataSource.apply(snapshot, animatingDifferences: true) But I facepalmed when I realized the smart thing to do is this: let items = [ Song(name: "A Song"), Song(name: "Another Song"), Song(name: "B Song"), Song(name: "B another Song") ] The question I have is, what would the snapshot logic look like such that I am minimizing the amount of times I have to instantiate items and sections? var snapshot = NSDiffableDataSourceSnapshot<LibrarySection, LibraryRow>() ??? dataSource.apply(snapshot, animatingDifferences: true) Thanks for any feedback you may have!!!
Replies
0
Boosts
0
Views
1.1k
Activity
Mar ’22
UICollectionViewCompositionalLayout
Hello, how should I perform two next two operations with UICompositionalLayout? Scroll To Specific offset Change layout of the item, I'm scrolling to. Whenever I try to call collectionView.collectionViewLayout.invalidateLayout(), I get reset: Content Offset of UICollectionView The layout change of the item is not updated Here is the example of the layout I try to use.    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                           heightDimension: .estimated(100))     let item = NSCollectionLayoutItem(layoutSize: itemSize)     item.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: nil, top: .fixed(8), trailing: nil, bottom: .fixed(8))     let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                            heightDimension: .estimated(100))     let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])     let section = NSCollectionLayoutSection(group: group)     return section And here is the example of cell class ReelTextCellView: UICollectionViewCell {   private var textView: UITextView!   private var infoHolderView: UIView!   private var copyButton: UIButton!   private var scrollView: UIScrollView!   private var heightConstraint: NSLayoutConstraint!   var isExpanded = false   override init(frame: CGRect) {     super.init(frame: .zero)     buildView()   }   required init?(coder: NSCoder) {     fatalError("init(coder:) has not been implemented")   }   override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {     let attributes = super.preferredLayoutAttributesFitting(layoutAttributes)     attributes.frame.size = .init(width: contentView.frame.width, height: isExpanded ? 300 : 100)     return attributes   } // Called with the cellWillAppear and manually for indexPathsForVisibleItems   func update(with appeareance: Appearance) {     isExpanded = appeareance.isExpanded     ///    heightConstraint.constant = appeareance.isExpanded ? 300 : 100   } private extension ReelTextCellView {   func buildView() {     infoHolderView = UIView()     contentView.addSubview(infoHolderView) {       contentView.bottomAnchor.constraint(equalTo: infoHolderView.bottomAnchor)       contentView.leadingAnchor.constraint(equalTo: infoHolderView.leadingAnchor)       contentView.trailingAnchor.constraint(equalTo: infoHolderView.trailingAnchor)       infoHolderView.heightAnchor.constraint(equalToConstant: 30)     }     let separatorView = UIView()     separatorView.backgroundColor = Assets.Colors.separator.color     infoHolderView.addSubview(separatorView) {       separatorView.topAnchor.constraint(equalTo: infoHolderView.topAnchor)       separatorView.leadingAnchor.constraint(equalTo: infoHolderView.leadingAnchor)       separatorView.trailingAnchor.constraint(equalTo: infoHolderView.trailingAnchor)       separatorView.heightAnchor.constraint(equalToConstant: 0.5)     }     textView = UITextView()     contentView.addSubview(textView) {       textView.topAnchor.constraint(equalTo: contentView.topAnchor)       textView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)       textView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)       textView.bottomAnchor.constraint(equalTo: infoHolderView.topAnchor)     }   } }
Replies
0
Boosts
0
Views
1.6k
Activity
Feb ’22
[once issue]there is large gap between collectionview contents and navigation controller
I have a collection view with custom layout. and it has different kinds of dynamic contents. suddenly when i tap on an item, go to next viewController and move back to collection view, there is a large gap between navigation controller and collection view content. could someone please share how to resolve this issue or how to find out the cause? please note that, collection view resides in a pageview controller
Replies
0
Boosts
0
Views
730
Activity
Feb ’22
ListView with personal data
I will briefly explain my view. My goal is to make a list where you can enter all personal information like a kind of emergency passport. There should also be text fields where you can tap on the plus button and then there is a new text field. On the top right I want to make an edit button that you can delete text fields again. I will connect this view with another SwiftUI view file. Does anyone have an idea how to solve this problem with the list? import SwiftUI struct ListeDaten: Identifiable { let id = UUID() let Name: String let Adresse: String var Telefonnummern: [String] = [] var Something: String = "" } struct ListeDaten: View {     var body: some View {                  TextField(Name: "Name/Vorname")         TextField(Adresse: "Adresse")         ForEach(id: \.self) {Telefonnummern in TextField("Telefonnummer")}         Button(action: {             Telefonnummern.append("")         })         {             Image(systemName: "plus.circle.fill")                 .foregroundColor(Color(.systemGreen))         }     } } struct ListeDaten_Previews: PreviewProvider {     static var previews: some View {         ListeDaten()     } }
Replies
0
Boosts
0
Views
706
Activity
Jan ’22
EPG data in a collectionview
I spoke to an Apple Engineer at WWDC 2021 about how to implement an EPG (Electronic Program Guide, see image below) in a collectionView. I was recommended to use a UICollectionViewCompositionalLayout where each program corresponds to an Item and each channel corresponds to a Section (the section being provided by a SectionProvider). Furthermore, I was told to override preferredLayoutAttributesFitting to set the size of each cell. However, I have two difficult issues that I have not been able to come around: I cannot figure out how to ensure the CollectionView displays all cells correctly at the right spot, such that the time is aligned vertically for all channels. I am using NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .estimated(estimatedWidth), heightDimension: .fractionalHeight(1))), which provides an estimated width, but this estimated width is apparently used for all cells not in the view, causing the cells to be rendered at the wrong spot as soon as I scroll to the right. The performance when scrolling is terrible, probably due to my overriding of preferredLayoutAttributesFitting on the cell, which causes the cell to change its width. I was instructed not to use "self sizing cells" as this would cause performance problems. But I cannot figure a way out of this. How do I tell the CollectionView how to render the cells at the proper spot and at the same time avoid "self sizing cells"? Any help would be highly appreciated!
Replies
0
Boosts
0
Views
1.3k
Activity
Jan ’22
UICollectionView with DiffableDataSource
Xcode 13.1, iOS 25 SDK I have a UICollectionView (with a custom UICollectionViewLayout) which I am updating with a DiffableDataSource. This CollectionView displays a particular data object (with a given number of sections and items). The user can choose to display a different object (with a different number of sections and items), reusing this CollectionView. When this occurs, I do the following: (pass the new data object to the custom layout) let layout = collectionView.collectionViewLayout layout.invalidateLayout() collectionView.contentSize = layout.collectionViewContentSize (calculate a new snapshot and apply it) When the new data object has FEWER sections and/or items as the first, I get a series of warning messages (one for each of the cells that are no longer in the collection view) as follows: 2021-12-07 14:29:02.239301-0600 WineCorner[82916:1921357] [CollectionView] Layout attributes <UICollectionViewLayoutAttributes: 0x7f77b3047e00> index path: (<NSIndexPath: 0xa0f0b1eb018e754a> {length = 2, path = 0 - 4}); frame = (578.118 6; 160 160); transform = [0.70710678118654757, -0.70710678118654746, 0.70710678118654746, 0.70710678118654757, 0, 0]; zIndex = 1; were received from the layout <WineCorner.WineRackLayout: 0x7f77b1f1a0c0> but are not valid for the data source counts. Attributes will be ignored. Obviously, I am not handling the situation correctly. What should I do so that these warning messages are not issued?
Replies
0
Boosts
0
Views
1.2k
Activity
Dec ’21
UICollectionView raises an exception when setting `layoutAttributesForElements` on iOS 15
Assertion failure in -[UICollectionView _setNeedsVisibleCellsUpdate:withLayoutAttributes:], UICollectionView.m:1511  I have the following structure here -| UITableView -| UITableViewCell   -| UICollectionView           -| UICollectionViewCell           -| UICollectionViewCell ... when I override func systemLayoutSizeFitting in TableViewCell, The crashed occurred.
Replies
0
Boosts
0
Views
801
Activity
Nov ’21
WWDC21-10252 how to pass data for specify cell type?
Hello, I can’t figure out to built in cell configuration in complicated scene. I have 3 type sections with 2 type cell (material and promo card for example) and 2 type of material cell size (main and general)… I would be pleased by your support to provide understanding that (
Replies
0
Boosts
0
Views
870
Activity
Nov ’21
tvOS 15 - Cell registration inside a diffable data source cell provider exception
What follows is about tvOS 15 but may also apply to iOS 15. Our app may display several types of UICollectionView cells and it depends on the content sent by our backend. Prior to tvOS 15, we used to lazily instantiate UICollectionView cell registrations when needed for the first time while building a UICollectionViewDiffableDataSource. Eventually, each cell registration is only instantiated once (or never). Now tvOS 15 throws an exception when doing so, pretending to prevent the app from creating a new cell registration each time. And it does not care whether it's actually a new cell registration each time or one that is lazily instantiated once. Here is the exception: *** Assertion failure in -[UICollectionView dequeueConfiguredReusableCellWithRegistration:forIndexPath:item:], UICollectionView.m:7413 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to dequeue a cell using a registration that was created inside -collectionView:cellForItemAtIndexPath: or inside a UICollectionViewDiffableDataSource cell provider. Creating a new registration each time a cell is requested will prevent reuse and cause created cells to remain inaccessible in memory for the lifetime of the collection view. Registrations should be created up front and reused. Registration: <UICollectionViewCellRegistration: 0x6000000f8c60>' I understand the concern but lazy instantiation is a thing and it should not be for forbidden for the sake of best practices that are not related to it. In my humble opinion, this assert should be removed and apps should be allowed to create cell registrations on the fly.
Replies
3
Boosts
0
Views
2.1k
Activity
Sep ’21
SwiftUI List section spacing
How to remove the spacing between List plain style section in swiftui iOS 15 struct ContentView: View {   var body: some View {     List {       Section {         Text("Hello, World!")         Text("Hello, World!")         Text("Hello, World!")       }       Section {         Text("Hello, World!")       }       Section {         Text("Hello, World!")         Text("Hello, World!")       } header: {         Text("section")       }     }.listStyle(.plain)   } }
Replies
1
Boosts
0
Views
8.3k
Activity
Sep ’21
App crashing while using collection view
I was trying to have a secondary collection view with circle images above (y axis) the functioning collection view but its crashing and throwing this error Error code: could not dequeue a view of kind: UICollectionElementKindCell with identifier CircleCollectionViewCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard ViewController code: // //  ViewController.swift //  Main_app // //  Created by Kushagr Agarwal on 23/08/21. // import UIKit class ViewController: UIViewController {     @IBOutlet var collectionView: UICollectionView!          @IBOutlet var topCollectionView: UICollectionView!          @IBOutlet weak var Leading: NSLayoutConstraint!          @IBOutlet weak var Trailing: NSLayoutConstraint!          @IBOutlet private weak var Menubutton: UIButton!     var menuOut = false               override func viewDidLoad() {         super.viewDidLoad()         // Do any additional setup after loading the view.         //self.navigationItem.titleView = UIImageView(image: UIImage(named: "Logo"))                  collectionView.register(MiddleCollectionViewCell.nib(), forCellWithReuseIdentifier: MiddleCollectionViewCell.identifier)                  collectionView.delegate=self         collectionView.dataSource=self                  topCollectionView.register(CircleCollectionViewCell.self, forCellWithReuseIdentifier: CircleCollectionViewCell.identifier)         topCollectionView.delegate=self         topCollectionView.dataSource=self //       Menu //       start                  let destructiveAction = UIAction(title: "Delete",image: UIImage(systemName: "nosign") , attributes: .destructive) { (_) in             print("Delete")         }                  let menu = UIMenu(title: "", children: [             UIAction (title: "Add New", image: UIImage(systemName: "plus.circle"), handler: { _ in  }),             UIAction (title: "Manage", image: UIImage(systemName: "hammer"), handler: { _ in  }),             destructiveAction         ])         self.Menubutton.menu = menu //    Menu end     } // Menu animation     @IBAction func MenuTap(_ sender: Any) {         if menuOut == false {             Leading.constant = -150             Trailing.constant = 150             menuOut = true         }         else{             Leading.constant = 0             Trailing.constant = 0             menuOut = false         }         UIView.animate(withDuration: 0.2, delay: 0.0 , options: .curveEaseIn,animations: {             self.view.layoutIfNeeded()         }){(animationComplete) in             print("Animation Completed")         }     } // Menu animation ends } // used for upper collection view extension ViewController: UICollectionViewDelegate {          func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {         collectionView.deselectItem(at: indexPath, animated: true )         print("btn tapped")              }           } extension ViewController: UICollectionViewDataSource {     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {         return 12     }     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MiddleCollectionViewCell.identifier, for: indexPath) as! MiddleCollectionViewCell         let topcell = collectionView.dequeueReusableCell(withReuseIdentifier: CircleCollectionViewCell.identifier, for: indexPath) as! CircleCollectionViewCell         topcell.configure(with: "")                  cell.configure(with: UIImage(named: "four")!)         return cell; topcell     } } //extension ViewController: UICollectionViewDelegateFlowLayout { // //}
Replies
1
Boosts
0
Views
2.1k
Activity
Sep ’21
how to transfer data from tableView to Collection View
I have TableView with section Each section have collection view I need to pass data from tableViewcontroller to Tableviewcell Please help me to pass the data between the controller Once I passed the data I will easily access the collection View Thank you in Advance. !
Replies
0
Boosts
0
Views
605
Activity
Jul ’21
Applying new snapshot to diffable data source in iOS 15 trigger unnecessary cell registration call
I try to figure out the improvement of apply(_:animatingDifferences:) function call without animation in iOS 15 Simulator. As log shown below, after removing an item and apply edited snapshot to diffable data source, it trigger several unnecessary calling to new cell that did not appear on screen. ENV: MacBook Air (M1, 2020), macOS Big Sur 11.4 (20F71) Xcode Version 13.0 beta (13A5154h), iOS 15.0 Simulator configure AlbumItemCell:(0x0000000128042400) at section:(0), item:(0) configure AlbumItemCell:(0x0000000125624aa0) at section:(0), item:(1) configure AlbumItemCell:(0x00000001280442a0) at section:(0), item:(2) configure AlbumItemCell:(0x0000000128045670) at section:(0), item:(3) configure AlbumItemCell:(0x0000000128050af0) at section:(0), item:(4) configure AlbumItemCell:(0x0000000125626430) at section:(0), item:(5) remove last items configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(0) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(1) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(2) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(3) configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(4)
Replies
6
Boosts
0
Views
5.9k
Activity
Jun ’21