UICollectionView 水平滚动静态焦点项目
UICollectionView Horizontal Scrolling With Static Focused Item
我正在尝试创建一个嵌入在 tvOS 上的 UITableViewCell 中的可水平滚动的 UICollectionView,并且已经实现了我的目标。
接下来我需要做的是让焦点转移到 UICollectionView 中的下一个项目,但是整个项目堆栈应该向左或向右移动一个位置,但焦点将保持不变在 'first' 项目视觉上。
这是我希望实现的 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 中,当我在遥控器上滑动到 select UICollectionView 中的下一个项目后,焦点应该留在左边,但下面的项目焦点应该移动一个。
有没有人对如何实现这一目标有任何提示?
我已经阅读了有关 UICollectionView 中粘性列的帖子,但我认为这不完全是粘性列?
我最近不得不为一个项目做这个。这是我使用的:
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)
}
}
从 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)
}
UICollectionViewDelegate
方法在焦点移动期间正在调用。所以要解决你的任务你需要操作UICollectionView(UIScrollView)的内容偏移量。要实现类似 'native' 的方式,您需要:
实施 UICollectionViewDelegate
方法 collectionView:didUpdateFocusInContext:withAnimationCoordiantor
,保存下一个焦点单元格 origin (x,y),并在 UIScrollViewDelegate
方法中 scrollViewWillEndDragging:withVelocity:targetContentOffset:
设置指向焦点单元格的新目标内容偏移量 origin.
@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
我正在尝试创建一个嵌入在 tvOS 上的 UITableViewCell 中的可水平滚动的 UICollectionView,并且已经实现了我的目标。
接下来我需要做的是让焦点转移到 UICollectionView 中的下一个项目,但是整个项目堆栈应该向左或向右移动一个位置,但焦点将保持不变在 'first' 项目视觉上。
这是我希望实现的 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 中,当我在遥控器上滑动到 select UICollectionView 中的下一个项目后,焦点应该留在左边,但下面的项目焦点应该移动一个。
有没有人对如何实现这一目标有任何提示?
我已经阅读了有关 UICollectionView 中粘性列的帖子,但我认为这不完全是粘性列?
我最近不得不为一个项目做这个。这是我使用的:
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)
}
}
从 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)
}
UICollectionViewDelegate
方法在焦点移动期间正在调用。所以要解决你的任务你需要操作UICollectionView(UIScrollView)的内容偏移量。要实现类似 'native' 的方式,您需要:
实施 UICollectionViewDelegate
方法 collectionView:didUpdateFocusInContext:withAnimationCoordiantor
,保存下一个焦点单元格 origin (x,y),并在 UIScrollViewDelegate
方法中 scrollViewWillEndDragging:withVelocity:targetContentOffset:
设置指向焦点单元格的新目标内容偏移量 origin.
@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