skip to Main Content

I have created a User Onboarding as a Collection View with 5 cells (pages).

I have 2 types of Collection View Items: welcomeCell which is always a first and single cell in Onboarding (indexPath.item == 0) and tutorialCell (all other cells) which has a tableView and can scroll its content vertically.

I want to add the next behaviour:

  1. user scrolls tableView content and swipes to the next page
  2. if user swipes back to the page he scrolled I want the page layout to be reloaded like it was initially set.

For now if a user swipes to the page he scrolled, he will see its position where he ended the scroll.

I suggests that collectionView content can be reloaded in didEndDisplaying method:

func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if indexPath.item != 0 {
        self.collectionView.reloadItems(at: [indexPath])
    }
}

But with this code I receive a strange cells behaviour: I can swipe up tableView on one page and the came content position will be on another page, but some page can be loaded with normal content position. Here is a GIF: GIF

I also tried collectionView.reloadData() in scrollViewDidScroll and scrollViewDidEndDecelerating but receive the similar behaviour.

Would you be so kind to share some experience and help to understand what’s the best practice for my case? Maybe I should find a way to not reload a page content at all, but reload imageView height anchor in constraints?

2

Answers


  1. Chosen as BEST ANSWER

    After some experiments and information research I ended up with following results:

    I slightly modified my initial goal: with below code if user, while swiping, will decide to stay on the current page, then data won't be reloaded. In other cases - reload.

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OnboardingCell", for: indexPath) as! OnboardingCollectionViewCell
    
            // reset the current tableView position to initial one
            if cell.tableView.window != nil {
            cell.tableView.contentOffset = CGPoint.zero
            cell.tableView.layoutIfNeeded()
            cell.tableView.reloadData()
            }
    
            return cell
    }
    
    
    private var activePage = 0 {
        didSet {
            if activePage != oldValue {
                // the method will fire cellForItemAt code
                collectionView.reloadData()
            }
        }
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        for cell in collectionView.visibleCells {
            activePage = collectionView.indexPath(for: cell)?.row ?? 0
        }
    }
    

    Also if you have a navigation controls, like previous and next buttons, don't forget to reload data like so:

    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        collectionView.reloadData()
    }
    

  2. Try with DispatchQueue method:

    if indexPath.item != 0 {
      DispatchQueue.main.async {
          self.collectionView.reloadData()
        }
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search