Swift 将collectionview中的活动单元格保持在一个位置

Swift 将collectionview中的活动单元格保持在一个位置,swift,xcode,uicollectionview,tvos,flowlayout,Swift,Xcode,Uicollectionview,Tvos,Flowlayout,我正在开发一个tvOS应用程序,希望collectionView的活动单元格始终处于相同的位置。换句话说,我不希望活动单元格通过我的collectionView,但我希望collectionView通过我的活动单元格 下图中的示例。活动标签始终位于屏幕中央,而您可以滚动collectionView以在那里获得不同的活动标签 基本上是一个带有自定义UI的pickerview。但不幸的是,iOS的pickerview没有在tvOS上提供 我已经查看了UICollectionViewScrollPo

我正在开发一个tvOS应用程序,希望collectionView的活动单元格始终处于相同的位置。换句话说,我不希望活动单元格通过我的collectionView,但我希望collectionView通过我的活动单元格

下图中的示例。活动标签始终位于屏幕中央,而您可以滚动collectionView以在那里获得不同的活动标签

基本上是一个带有自定义UI的pickerview。但不幸的是,iOS的pickerview没有在tvOS上提供

我已经查看了
UICollectionViewScrollPosition.VerticallyCenter
。这部分让我达到了目的,但这还不够。如果我滚动得很快,活动项会在列表中跳得更远,当我暂停时,它会一直向上滚动到中间。我真的希望活动项始终位于屏幕中央

有什么办法吗


根据@HMHero-answer更新

好吧,我试着按你说的做,但无法让滚动正常工作。这可能是因为我计算了偏移量,或者(就像你说的)
setContentOffset(,动画:)
不起作用

现在我做了以下几件事,不知道从这里该往哪里走

禁用滚动并将最后一个和第一个标签居中

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
}
获取标签的位置以检索距屏幕中心的距离(偏移量)

打印时,偏移量返回100的增量。标签的高度为90,间距为10。所以我认为这是正确的,尽管它一直运行到2400(最后一个标签)


有什么想法吗?

我在tvOS上工作已经一年多了,但我记得这应该是一个相当简单的技巧。也许有更好的方法可以通过更新的api实现这一点,但我就是这么做的

1) 禁用在集合视图上滚动IsCrollenabled=false

2) 在委托中,可选的公共函数collectionView(collectionView:UICollectionView,didUpdateFocusIn上下文:UICollectionViewFocusUpdateContext,带协调器:UIFocusAnimationCoordinator),获取nextFocusedIndexPath并计算位于集合视图中心的单元格偏移量

3) 使用偏移量,在代理回调中手动设置滚动动画

我找到了我有主意的旧帖子


最后,我做的与文章中的答案有些不同,但这是一个很好的提示。

我在tvOS上工作已经一年多了,但我记得,用一个简单的技巧应该相当简单。也许有更好的方法可以通过更新的api实现这一点,但我就是这么做的

1) 禁用在集合视图上滚动IsCrollenabled=false

2) 在委托中,可选的公共函数collectionView(collectionView:UICollectionView,didUpdateFocusIn上下文:UICollectionViewFocusUpdateContext,带协调器:UIFocusAnimationCoordinator),获取nextFocusedIndexPath并计算位于集合视图中心的单元格偏移量

3) 使用偏移量,在代理回调中手动设置滚动动画

我找到了我有主意的旧帖子


我最终做的与线程中的答案有些不同,但这是一个很好的提示。

好的,加上@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()
        })

    }
}

好的,连同@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()
        })

    }
}

我想我明白你的意思了。您正在根据返回的索引设置滚动动画,而不是让活动项影响滚动。我已经知道第1步和第2步该做什么,但第3步是我必须研究的。我明天/星期天拿到项目时会这样做。我们会把进度反馈给你的!谢谢你的投入!在步骤3中,我记不清它是什么,但它并不是简单地运行setContentOffset(,animated:)。如果你不明白,我会试试。我已经用你的想法更新了我的代码。有两件事让我陷入困境。我不确定这是否是计算单元格偏移量的正确方法。我不知道如何用这种方式手动设置卷轴的动画。任何帮助都将不胜感激!我的背景更多的是设计,但我正在努力学习一些代码:)@Wouter125我链接了我发现这个想法的旧帖子。你可能需要做出调整。既然你给我指明了正确的方向,我就赏金给你了。我接受了我自己的答案,因为它包含了解决方案本身。希望你能接受这个!再次感谢@HMHero:)我想我明白你的意思了。您正在根据返回的索引设置滚动动画,而不是让活动项影响滚动。我已经知道第1步和第2步该做什么,但第3步是我必须研究的。我明天/星期天拿到项目时会这样做。我们会把进度反馈给你的!谢谢你的投入!在步骤3中,我记不清它是什么,但它并不是简单地运行setContentOffset(,animated:)。如果你不明白,我会试试。我已经用你的想法更新了我的代码。有两件事让我陷入困境。我不确定这是否是计算单元格偏移量的正确方法。我不知道如何用这种方式手动设置卷轴的动画。任何帮助都将不胜感激!我的背景更多的是设计,但我正在努力学习一些代码:)@Wouter125我链接了我发现这个想法的旧帖子。你可能需要做出调整。既然你给我指明了正确的方向,我就赏金给你了。我接受了我自己的答案,因为它包含了解决方案本身。希望你能接受这个!再次感谢@HMHero