有没有办法更改集合视图中的聚焦索引路径?

Is there a way to change the focused index path in a collection view?

我正在构建一个类似“照片”的应用,您可以在其中滚动 UICollectionView 中的照片缩略图,您可以点击其中一张照片以全屏查看该照片,然后滑动以在照片之间移动。我正在努力添加对键盘导航的支持,以便您可以使用箭头键 select 一张照片,点击 space 全屏查看,使用箭头键在全屏照片之间移动, 然后点击 space 关闭它。这在照片应用程序中运行良好,但在我的应用程序中,当您关闭全屏视图控制器时,焦点不会在底层视图控制器中更新到您刚刚关闭的照片的索引路径 - 它显然只知道索引在该视图控制器中最后聚焦的路径,即在按下 space 之前聚焦的路径。当全屏视图控制器被关闭时,我似乎需要手动将焦点移动到可能不同的索引路径。你是怎么做到的?

为了启用焦点,我在 UICollectionViewController:

中设置了这些
collectionView.allowsFocus = true
collectionView.allowsFocusDuringEditing = true
collectionView.remembersLastFocusedIndexPath = true
restoresFocusAfterTransition = true

我已经尝试了以下但焦点没有移动到该单元格,即使我将 remembersLastFocusedIndexPathrestoresFocusAfterTransition 设置为 false:

cell.focusGroupPriority = .currentlyFocused
cell.setNeedsFocusUpdate()
cell.updateFocusIfNeeded()
cell.becomeFirstResponder()

如果已经有聚焦索引路径,则可以更改聚焦索引路径。

为此,将集合视图委托方法indexPathForPreferredFocusedView(in:) 实现到return 您要关注的索引路径。当您想要更改焦点时,调用 collectionView.setNeedsFocusUpdate(),系统将调用该函数,让您有机会指定焦点的索引路径。注意 iOS 现在将要求您的应用程序告诉它最初要关注的索引路径以及焦点状态的变化。您可以 return nil 让系统决定关注哪个。

请注意,您不能将 collectionView.remembersLastFocusedIndexPath 设置为 true,否则这将不起作用。要拥有该功能,您需要使用 collectionView(_:didUpdateFocusIn:with:) 和 return 中的 indexPathForPreferredFocusedView(in:).

手动跟踪最后一个聚焦索引路径
func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? {
    return lastFocusedIndexPath
}

func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
    lastFocusedIndexPath = context.nextFocusedIndexPath
}

private func moveFocus(to indexPath: IndexPath) {
    lastFocusedIndexPath = indexPath
    collectionView.setNeedsFocusUpdate()
    //collectionView.updateFocusIfNeeded() //can update it now if you need it to
}