Храните активную ячейку в виде коллекции в одном месте
Я работаю над приложением tvOS, где я хочу, чтобы активная ячейка collectionView всегда находилась в одной и той же позиции. Другими словами, я не хочу, чтобы активная ячейка проходила через мой collectionView, но я хочу, чтобы collectionView проходил через мою активную ячейку.
Пример на следующем рисунке. Активная метка всегда находится в центре экрана, в то время как вы можете прокручивать collectionView, чтобы получить другую активную метку там.
В основном это окно выбора с пользовательским интерфейсом. Но, к сожалению, в tvOS нет возможности выбора iOS.
Я уже посмотрел в UICollectionViewScrollPosition.verticallyCentered
, Это частично приводит меня туда, но этого недостаточно. Если я прокручиваю очень быстро, активный элемент прыгает дальше вниз по списку, а когда я делаю паузу, он прокручивается до самого центра. Я действительно хочу, чтобы активный элемент всегда был в центре экрана.
Есть идеи, как это сделать?
Обновление на основе ответа @HMHero
Хорошо, я пытался сделать то, что вы сказали мне, но не могу заставить прокрутку работать должным образом. Возможно, это связано с моим расчетом смещения или потому что (как вы сказали) setContentOffset(, animated: )
не работает
Прямо сейчас я сделал следующее и не уверен, куда идти отсюда;
Отключите прокрутку и отцентрируйте последний и первый ярлык
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
}
Получение положения метки для получения расстояния от центра экрана (смещение)
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
}
}
Смещение возвращает приращения 100 при печати. Высота надписей равна 90, а расстояние между ними равно 10. Поэтому я подумал, что это будет правильно, хотя он проходит до 2400 (последняя метка).
Любые идеи о том, куда идти отсюда?
2 ответа
Хорошо, наряду с некоторыми указателями @HMHero я достиг желаемого эффекта. Это включало анимацию contentOffset с помощью пользовательской анимации. Это мой код;
func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
if let previousIndexPath = context.previouslyFocusedIndexPath,
let cell = countryCollectionView.cellForItem(at: previousIndexPath) {
UIView.animate(withDuration: 0.3, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
cell.contentView.alpha = 0.3
cell.contentView.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
})
}
if let indexPath = context.nextFocusedIndexPath,
let cell = countryCollectionView.cellForItem(at: indexPath) {
let cellCenter = CGPoint(x: cell.bounds.origin.x + cell.bounds.size.width / 2, y: cell.bounds.origin.y + cell.bounds.size.height / 2)
let cellLocation = cell.convert(cellCenter, to: self.countryCollectionView)
let centerView = countryCollectionView.frame.midY
let contentYOffset = cellLocation.y - centerView
UIView.animate(withDuration: 0.3, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
collectionView.contentOffset.y = contentYOffset
cell.contentView.alpha = 1.0
cell.contentView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
self.countryCollectionView.layoutIfNeeded()
})
}
}
Прошло уже больше года с тех пор, как я работал над tvOS, но, насколько я помню, все должно быть довольно просто с простым приемом. Там может быть лучший способ сделать это с обновленным API, но это то, что я сделал.
1) Отключить прокрутку в представлении коллекции isScrollEnabled = false
2) В делегате необязательный общедоступный func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, с координатором: UIFocusAnimationCoordinator), получают nextFocusedIndexPath и вычисляют смещение ячейки, которое будет в центре представления коллекции.
3) Со смещением, анимируйте прокрутку вручную в обратном вызове делегата.
Я нашел старый пост, где у меня появилась идея.
Как отцентрировать UICollectionViewCell, который был сфокусирован?
Я закончил тем, что сделал немного отличающийся от ответа в потоке, но это был хороший намек.