在某些情况下,在tvOS上,集合视图会将焦点重新设置为reloadData()
。下面是重现该问题的最小代码量。
import SwiftUI
@main
struct DemosApp_tvOS: App {
var body: some Scene {
WindowGroup {
HomeView()
}
}
}
public struct HomeView: UIViewControllerRepresentable {
public func makeUIViewController(context: Context) -> HomeViewController { .init() }
public func updateUIViewController(_ uiViewController: HomeViewController, context: Context) { }
}
public final class HomeViewController: UIViewController {
public override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.present(CollectionViewController(collectionViewLayout: UICollectionViewFlowLayout()), animated: true)
}
}
}
public final class CollectionViewController: UICollectionViewController {
public override func viewDidLoad() {
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
public override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesEnded(presses, with: event)
if presses.contains(where: { $0.type == .playPause }) {
collectionView.reloadData()
}
}
public override func numberOfSections(in collectionView: UICollectionView) -> Int { 1 }
public override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 7 }
public override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = .gray
cell.layer.borderColor = UIColor.blue.cgColor
return cell
}
public override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
present(UIViewController(), animated: true)
}
public override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
context.previouslyFocusedView?.layer.borderWidth = 0
context.nextFocusedView?.layer.borderWidth = 4
}
}
基本上,需要满足以下条件:
- 集合视图VC被呈现在另一个VC的顶部(例如,许多应用程序都有主屏幕)
- 用户选择除第一项以外的任何项
- 从集合视图中选择一个项目会显示另一个VC(让我们称之为细节VC)
- 用户忽略细节VC
- 在返回到集合视图屏幕之后,某些事件触发
reloadData
调用(在上面的示例中,按下远程播放/暂停按钮将重新加载集合视图)。
在reloadData()
调用发生之前,焦点正确地保持在所选项目上。
但是,一旦reloadData()
调用发生,焦点就会重置到第一个单元格。而且这种情况只发生在从细节VC返回后的第一次。
随后的数据重载不会重置焦点,唯一有问题的调用是在细节VC被解散后的第一次重载。
此外,如果集合视图VC没有在另一个VC上以模态方式呈现,则不会发生重新加载问题。
有人知道解决这个问题的方法吗?一个不涉及重新设计UI层次结构的方法。
P.S.我试着玩弄shouldUpdateFocus(in:)
和indexPathForPreferredFocusedView(in:)
委托方法,但没有成功。
1条答案
按热度按时间h6my8fg21#
我就此提交了一份苹果报告(FB13262879),同时我搜索了一个变通方案,并找到了一个。
解决方法包括设置
collectionView.remembersLastFocusedIndexPath = false
,并“手动”管理集合视图焦点:难题的最后一部分是强制集合视图在错误地重置焦点后恢复焦点:
这不是一个很好的解决办法,可能会在未来打破,希望苹果修复UIKit的错误。