3

I have a UICollectionView in my tvOS application populated with several UICollectionViewCells, which in turn, contain a UICollectionView with items of their own inside.

The container UICollectionView scrolls vertically, whilst the inner UICollectionView scrolls horizontally. Focus is disabled for the top level UICollectionViewCells, and is passed into the items within the inner UICollectionView.

What it looks like, resembles this:

-------------------
|                 |
| --------------- |
| | xxxx xxxx xx| |
| | xxxx xxxx xx| |
| --------------- |
|                 |
| --------------- |
| | xxxx xxxx xx| |
| | xxxx xxxx xx| |
| --------------- |
|                 |
-------------------

What I'm trying to achieve here is when focus occurs on a row that is below the vertical centerline of the UICollectionView, the row should be vertically centered in the UICollectionView.

Before centering vertically
-------------------
| 1xxx xxxx xxxx x|
| 1xxx xxxx xxxx x|
|                 |
| 2xxx xxxx xxxx x|
| 2xxx xxxx xxxx x|
|                 |
| 3xxx xxxx xxxx x| <-
| 3xxx xxxx xxxx x| <-
|                 |
| 4xxx xxxx xxxx x|
-------------------

=

After centering vertically
-------------------
|                 |
| 2xxx xxxx xxxx x|
| 2xxx xxxx xxxx x|
|                 |
| 3xxx xxxx xxxx x|
| 3xxx xxxx xxxx x|
|                 |
| 4xxx xxxx xxxx x|
| 4xxx xxxx xxxx x|
|                 |
-------------------

Does anyone have a comment/suggestion on how I could achieve this?

Edit: Based on another SO post, I have tried to implement the following UICollectionViewDelegate function, but it does not seem to work for me:

func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        if let indexPath = context.nextFocusedIndexPath,
            let _ = collectionView.cellForItem(at: indexPath) {
            collectionView.contentInset.top = max((collectionView.frame.height - collectionView.contentSize.height) / 2, 0)
        }
    }

Edit: After some trial and error leading from the suggested answer below, I've gotten it to work with the following code:

func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        if let indexPath = context.nextFocusedIndexPath {
            collectionView.isScrollEnabled = false

            coordinator.addCoordinatedAnimations({
                self.collectionView.scrollToItem(at: indexPath, at: .centeredVertically, animated: true)
            }, completion: nil)
        }
    }
Earthling
  • 283
  • 5
  • 17

1 Answers1

1

You can use the scrollToItemAtIndexPath method like this :

func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
    if let indexPath = context.nextFocusedIndexPath,
        let _ = collectionView.cellForItem(at: indexPath) {
        self.collectionView.scrollToItem(at: indexPath, at: 
         .centeredVertically, animated: true)
    }
}

EDITED

Some how you will have to extract the indexPath from the cell, using the accessiblity properties or something else, than you can scroll to that indexPath like this :

override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
    if let nextCell = context.nextFocusedView as? ScrumCollectionViewCell {
        let index = Int(nextCell.accessibilityHint!)!
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { // 2
            self.collectionView.scrollToItem(at: IndexPath(item: index, section: 0), at: .centeredVertically, animated: true)
        }
    }
}
Shahzaib Qureshi
  • 989
  • 8
  • 13
  • Thanks for suggesting that, but it does not seem to help; the cell is still not being centered vertically, strangely enough. – Earthling Aug 02 '18 at 06:24
  • After some trial and error, I've gotten it to work by extending this answer, to which I will post my completed code in my original question. Marking this as the answer. – Earthling Aug 02 '18 at 07:14
  • I have also found a solution to this, i am editing my answer. – Shahzaib Qureshi Aug 02 '18 at 07:31