'Show hints for new users in collectionView in iOS

I'm trying to create hints for new users in iOS application, like to open profile click here, etc. I have a collection view and inside it I have elements that I fetch from server. I need to show hint near the first element. My code:

var tipView = EasyTipView(
        text: "Выбирай предмет и начинай обучение",
        preferences: EasyTipView.globalPreferences
    )

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let section = sections[indexPath.section]
        
        switch section {
            
        case .fav_subjects:
            
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FavSubjectsCollectionViewCell", for: indexPath) as! FavSubjectsCollectionViewCell
            let favSubjects = model[.fav_subjects] as! [Subjects.FavSubject]
            let cellModel = favSubjects[indexPath.item]
            cell.configure(with: cellModel)

              //here I'm trying to render hint near first element of collectionView  
            if indexPath.section == 0 && indexPath.item == 0 {
                 let view = cell.contentView
                 tipView.show(forView: view)
                        }
            return cell
            
       case .all_subjects:
            
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AllSubjectsCollectionViewCell", for: indexPath) as! AllSubjectsCollectionViewCell
            
            let  allSubjects = model[.all_subjects] as! [Subjects.Subject]
            let cellModel = allSubjects[indexPath.item]
            cell.configure(with: cellModel)
            return cell
        }
    }

}

My problem is when I open screen for the first time my hint displays on the top of the screen and not near the first element, but when I switch to another screen and then go back, hint displays exactly where expected.

I suggest that my problem is screen rendered for the first time before all items fetched from server so tried to use layoutIfNeeded() to rerender when the size is changed but it doesn't help:

tipView.layoutIfNeeded()
if indexPath.section == 0 && indexPath.item == 0 {
      let view = cell.contentView
      self.tipView.layoutIfNeeded()
      self.tipView.show(forView: view)
}

Also I have tried to use viewDidAppear, because I thought that if screen is already rendered than I will have element rendered and I will show hint in the right place for the first render but it turns out that in viewDidAppear cell is nil:

override func viewDidAppear(_ animated: Bool) {
   super.viewDidAppear(animated)
   let cell = collectionView.cellForItem(at: IndexPath(item: 0, section: 0))
}

Incorrect(when screen opened first time): enter image description here

Correct: enter image description here

I'm new to iOS so I think I missed something important, please help.



Solution 1:[1]

The method cellForItem(at:) gets called before the cells gets displayed on screen. In fact, at this point the final frame of the cell is not yet determined, it will happen later when the cell gets added to the view hierarchy and the layout pass happens.

In some cases even if cellForItem(at:) gets called, the cell may never appear on screen.

If you always display the hint near the first element, perhaps it will be easier to use the collection view's frame as reference instead of the first cell unless you need the hint to scroll along with the cell.

Alternatively, add the hint as a subview to the cell's contentView and use Auto Layout to define its position inside the cell. Don't forget to remove the hint from the view hierarchy when appropriate because the same cell may end up being dequeued for another index path during scroll.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vadim Belyaev