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