Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42642

Incomplete delete animation for a single row horizontal UICollectionView with UICollectionViewCompositionalLayout

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)

Upvotes: 4

Views: 281

Answers (3)

Asperi
Asperi

Reputation: 257493

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)
}

Upvotes: 2

Mrunal
Mrunal

Reputation: 14118

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)
}

Upvotes: 0

Ozone
Ozone

Reputation: 1353

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();

Upvotes: 0

Related Questions