UICollectionView 水平滚动与静态焦点项目
Posted
技术标签:
【中文标题】UICollectionView 水平滚动与静态焦点项目【英文标题】:UICollectionView Horizontal Scrolling With Static Focused Item 【发布时间】:2018-06-28 05:02:02 【问题描述】:我正在尝试在 tvOS 上的 UITableViewCell 中创建一个可水平滚动的 UICollectionView,并且已经实现了我的目标。
接下来我需要做的是能够将焦点转移到 UICollectionView 中的下一个项目,但是整个项目堆栈应该向左或向右移动一个位置,但焦点将保持在视觉上的“第一个”项目。
这是我希望实现的一个小的 ASCII 图表:
Scenario 1, before focus shifts
---------------------
1. | v v v v v |
2. |[v] v v v v |
3. | v v v v v |
---------------------
Scenario 1, after focus shifts
---------------------
1. | v v v v v |
2. | v [v] v v v |
3. | v v v v v |
---------------------
上述场景 1 是默认行为,焦点转移到 UICollectionView 中的下一项。
Scenario 2, before focus shifts
---------------------
1. | v v v v v |
2. |[v] v v v v |
3. | v v v v v |
---------------------
Scenario 2, after focus shifts
---------------------
1. | v v v v v |
2. v |[v] v v v |
3. | v v v v v |
---------------------
在场景2中,我在遥控器上滑动选择UICollectionView中的下一个项目后,焦点应该保持在左侧,但焦点下方的项目应该移动一个。
有人对如何实现这一点有任何提示吗?
我在 UICollectionView 中阅读了关于粘性列的帖子,但我认为这不完全是粘性列?
【问题讨论】:
【参考方案1】:我最近不得不为一个项目这样做。这是我使用的:
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator)
if let focusView = context.nextFocusedView as? UICollectionViewCell, let indexPath = collection.indexPath(for: focusView)
collection.isScrollEnabled = false
coordinator.addCoordinatedAnimations(
self.collection.scrollToItem(at: indexPath, at: .left, animated: true)
, completion: nil)
【讨论】:
不错!不过有一个问题:content
做什么,第三个let
条件?还有,为什么要把isScrollEnabled
设置成false
?
抱歉,这是我在 viewController 中的数据源。除非您有可选数据,否则您不需要它。我将其设置为错误,因为用户可能会尝试在动画转换中间滚动到不同的索引并让 collectionView 奇怪地滚动。您可以将其设置为 false 以查看是否有相同的结果。【参考方案2】:
从 tvOS 13 开始,您可以使用 UICollectionViewCompositionalLayout 的 UICollectionLayoutSectionOrthogonalScrollingBehavior(.groupPagin) 来处理水平滚动的静态焦点。 只需在组中添加一项!
private func createCollectionViewLayout() -> UICollectionViewLayout
let sectionProvider =
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(100), heightDimension: .absolute(100))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPaging
return section
return UICollectionViewCompositionalLayout(sectionProvider: sectionProvider)
【讨论】:
【参考方案3】:UICollectionViewDelegate
方法在焦点移动期间被调用。因此,要解决您的任务,您需要操作 UICollectionView 的 (UIScrollView) 内容偏移量。要实现类似“本机”的方式,您需要:
实现UICollectionViewDelegate
方法collectionView:didUpdateFocusInContext:withAnimationCoordiantor
,保存下一个焦点单元格origin (x,y),并在UIScrollViewDelegate
方法scrollViewWillEndDragging:withVelocity:targetContentOffset:
中设置新的目标内容偏移量,指向焦点单元格起源。
@interface CLViewController () <UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonatomic) CGPoint focusedCellPosition;
@end
@implementation CLViewController
- (void)collectionView:(UICollectionView *)collectionView didUpdateFocusInContext:(UICollectionViewFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
NSIndexPath *next = context.nextFocusedIndexPath;
self.focusedCellPosition = [collectionView cellForItemAtIndexPath:next].frame.origin;
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
*targetContentOffset = self.focusedCellPosition;
@end
【讨论】:
以上是关于UICollectionView 水平滚动与静态焦点项目的主要内容,如果未能解决你的问题,请参考以下文章