Keep active cell in collectionview in one place

Question

I'm working on a tvOS application where I want the active cell of a collectionView always in the same position. In other words, I don't want the active cell to go through my collectionView but I want the collectionView to go through my active cell.

Example in the following image. The active label is always in the center of the screen while you can scroll the collectionView to get a different active label over there.

Basically a pickerview with a custom UI. But the pickerview of iOS is unfortunately not provided on tvOS...

Active Cell

I've already looked into UICollectionViewScrollPosition.verticallyCentered. That partially gets me there but it isn't enough. If I scroll really fast, the active item jumps further down the list and when I pause it scrolls up all the way to the center. I really want the active item to be in center of the screen at all times.

Any ideas on how to do this?


Update based on @HMHero answer

Okay, I tried to do what you told me, but can't get the scrolling to work properly. This is perhaps due to my calculation of the offset, or because (like you said) setContentOffset(, animated: ) doesn't work.

Right now I did the following and not sure where to go from here;

Disable scrolling and center last and first label

override func viewDidLoad() {
    super.viewDidLoad()
    //Disable scrolling
    self.collectionView.isScrollEnabled = false
    //Place the first and last label in the middle of the screen
    self.countryCollectionView.contentInset.top = collectionView.frame.height * 0.5 - 45
    self.countryCollectionView.contentInset.bottom = collectionView.frame.height * 0.5 - 45
}

Getting the position of a label to retrieve the distance from the center of the screen (offset)

func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
if let indexPath = context.nextFocusedIndexPath,
        let cell = countryCollectionView.cellForItem(at: indexPath) {
            //Get the center of the next focused cell, and convert that to position in the visible part of the (tv) screen itself
            let cellCenter = countryCollectionView.convert(cell.center, to: countryCollectionView.superview)
            //Get the center of the collectionView
            let centerView = countryCollectionView.frame.midY
            //Calculate how far the next focused cell y position is from the centerview. (Offset)
            let offset = cellCenter.y - centerView
    }
}

The offset returns incrementals of 100 when printing. The labels' height is 90, and there is a spacing of 10. So I thought that would be correct although it runs through all the way up to 2400 (last label).

Any ideas on where to go from here?


Show source
| xcode   | swift   | uicollectionview   | tvos   | flowlayout   2017-08-17 23:08 1 Answers

Answers to Keep active cell in collectionview in one place ( 1 )

  1. 2017-08-19 00:08

    It's been more than a year since I worked on tvOS but as I remember it should be fairly simple with a simple trick. There might be a better way to do this with updated api but this is what I did.

    1) Disable to scroll on collection view isScrollEnabled = false

    2) In delegate, optional public func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator), get nextFocusedIndexPath and calculate the offset of the cell to be at the center of the collection view.

    3) With the offset, animate the scroll manually in the delegate callback.

    I found the old post where I got an idea.

    How to center UICollectionViewCell that was focused?

    I ended up doing somewhat different from the answer in the thread but it was a good hint.

Leave a reply to - Keep active cell in collectionview in one place

◀ Go back