4

Currently, I have a single row horizontal UICollectionView with UICollectionViewCompositionalLayout

[All] [Calendar] [Home2] [Work3] [Work4] ... [Work8] [⚙]

The UICollectionView, is acting as a scrollable Tab layout navigation bar.

When user switch to [⚙] page, he is able to delete the tab before itself. In this case, during the 1st time of the delete operation, tab [Work8] will be removed.

Here's the straightforward code to achieve so.


https://github.com/yccheok/ios-tutorial/blob/debug/TabDemo/TabDemo/ViewController.swift#L144

func debug() {
    if tabInfos.count < 2 {
        return
    }
    
    let index = tabInfos.count-2
    tabInfos.remove(at: index)
    let indexPath = getIndexPath(index)
    self.tabCollectionView.deleteItems(at: [indexPath])
    
    // TODO: Possible solution.
    /*
    self.tabCollectionView.reloadData()
    DispatchQueue.main.async() {
        let indexPath = self.getIndexPath(self.tabInfos.count-1)
        self.tabCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
        self.tabCollectionView.scrollToItem(at: indexPath, at: .right, animated: true)
    }
     */

    // Clear left/ right cached view controllers - https://stackoverflow.com/a/21624169/72437
    pageViewController.dataSource = nil
    pageViewController.dataSource = self

    // Don't forget to adjust the selection index.
    if index < self.selectedTabInfoIndex {
        selectedTabInfoIndex -= 1
    }
}

Strange outcome

https://www.youtube.com/watch?v=Wzgb4QErUes (Please refer to this video for complete deletion animation)

This is how it looks like before deletion

enter image description here

As you can see in the video, after the deletion of [Work8], the left side tab ([Work3]) is not visible

enter image description here

My expected outcome is, [Work3] should be visible too immediately, without any additional action from user. I need to tap on the UICollectionView, move it abit, only all the tabs will appear

enter image description here


I prefer not to use reloadData, as

  1. It will not preserve scroll position of UICollectionView.
  2. It does not have animation.

Do you have any idea what is the root cause of this strange animation outcome?

Here's the complete source code to try it out - https://github.com/yccheok/ios-tutorial/tree/debug (Folder TabDemo)

Asperi
  • 228,894
  • 20
  • 464
  • 690
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • It would be nice if you upload a simple reproducible project on git and link it here – Mojtaba Hosseini Sep 12 '20 at 09:26
  • I already posted it https://github.com/yccheok/ios-tutorial/releases/tag/debug (Under folder https://github.com/yccheok/ios-tutorial/tree/debug (Folder TabDemo) – Cheok Yan Cheng Sep 12 '20 at 11:34
  • I downloaded your demo project, compiled it with Xcode Version 12.0 beta 5 (12A8189h), and run it on the iPhone 11 Pro simulator. When I tap Delete in the Settings tab, the Work 3 tab is displayed correctly. – Reinhard Männer Sep 12 '20 at 19:18

3 Answers3

2

You need to configure layout a bit differently - use explicit configuration instead of orthogonal behavior.

Here is fixed part. Tested with Xcode 11.7 / iOS 13.7

demo

private func layoutConfig() -> UICollectionViewCompositionalLayout {
    let configuration = UICollectionViewCompositionalLayoutConfiguration()
    configuration.scrollDirection = .horizontal
    return UICollectionViewCompositionalLayout(sectionProvider: { (sectionNumber, env) -> NSCollectionLayoutSection? in
        let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(44), heightDimension: .fractionalHeight(1))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(44), heightDimension: .absolute(44))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = 1
        return section
    }, configuration: configuration)
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • I thought I need to use `section.orthogonalScrollingBehavior = .continuous` to achieve horizontal scrolling. I do not notice this `configuration.scrollDirection = .horizontal` technique. Thanks for telling me. – Cheok Yan Cheng Sep 14 '20 at 03:47
0

It has not been drawn yet because it was out of viewport when you clicked delete for Work8. This is typical for iOS.

You could force a redraw rather than a reloadData:

myViewOrComponent.setNeedsDisplay();
Ozone
  • 1,337
  • 9
  • 18
0

Can you please give a try with this, here you may require to handle scrollable contentSize and scrollPosition.

func debug() {
    if tabInfos.count < 2 {
        return
    }
    
    let index = tabInfos.count-2
    tabInfos.remove(at: index)
    var indexPath = getIndexPath(index)
    self.tabCollectionView.deleteItems(at: [indexPath])
    tabCollectionView.collectionViewLayout = layoutConfig()

    print(selectedTabInfoIndex)

    // Don't forget to adjust the selection index.
    if index < self.selectedTabInfoIndex {
        selectedTabInfoIndex -= 1
    }
    indexPath = getIndexPath(selectedTabInfoIndex)
    self.selectTab(selectedTabInfoIndex)
}
Mrunal
  • 13,982
  • 6
  • 52
  • 96