Reputation: 293
I have a UICollectionView
in my tvOS application populated with several UICollectionViewCell
s, 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 UICollectionViewCell
s, 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)
}
}
Upvotes: 3
Views: 1283
Reputation: 920
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)
}
}
}
Upvotes: 1