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 水平滚动与静态焦点项目的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView - 水平滚动,水平布局?

如何检测滚动到水平 UICollectionView 的末尾

在 UICollectionView 中禁用水平滚动

UICollectionView 中的垂直和水平滚动方向

UICollectionView 水平滚动

UICollectionView 水平滚动特定列