Храните активную ячейку в виде коллекции в одном месте

Я работаю над приложением 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, который был сфокусирован?

Я закончил тем, что сделал немного отличающийся от ответа в потоке, но это был хороший намек.

Другие вопросы по тегам