indexPathForPreferredFocusedView未被调用

时间:2018-02-02 15:31:54

标签: uicollectionview focus tvos apple-tv

我需要指定哪个细胞应该获得焦点。

根据Apple文档,如果indexPathForPreferredFocusedView属性为remembersLastFocusedIndexPath,或者如果没有保存的索引路径,则应调用false委托方法,因为之前没有关注任何单元格。

在我的情况下,我在UIViewController中使用了一个集合视图,并将remembersLastFocusedIndexPath设置为false,但未调用indexPathForPreferredFocusedView

如何解释这种行为?

6 个答案:

答案 0 :(得分:5)

The function indexPathForPreferredFocusedView is part of UICollectionViewDelegate, so it might be that the delegate was not assigned to your collectionView.

Or, the problem might also be on the focus environment, not taking into account your UICollectionView.

As a reference, here you have an example of a simple collectionView with 5 cells, having the one in the center initially selected by default

import UIKit

class ViewController: UIViewController {

    private var collectionView: UICollectionView!
    private var items = ["One", "Two", "Three", "Four", "Five"]

    override var preferredFocusEnvironments: [UIFocusEnvironment] {
        return [collectionView]
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: UICollectionViewFlowLayout())
        collectionView.remembersLastFocusedIndexPath = false
        MyCell.register(in: collectionView)
        view.addSubview(collectionView)

        collectionView.dataSource = self
        collectionView.delegate = self
    }
}

extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCell.reuseIdentifier, for: indexPath) as! MyCell
        cell.titleLabel.text = items[indexPath.row]
        return cell
    }
}

extension ViewController: UICollectionViewDelegate {

    func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? {
            return IndexPath(row: 2, section: 0)
    }
}

class MyCell: UICollectionViewCell {

    static var reuseIdentifier: String { return String(describing: self) + "ReuseIdentifier" }

    var titleLabel: UILabel!

    public static func register(in collectionView: UICollectionView) {
        collectionView.register(MyCell.self, forCellWithReuseIdentifier: MyCell.reuseIdentifier)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        titleLabel = UILabel(frame: bounds)
        backgroundColor = .blue
        contentView.addSubview(titleLabel)
    }

    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        backgroundColor = isFocused ? .red : .blue
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

collectionView

答案 1 :(得分:2)

Swift 4: 我遇到了同样的问题。我想重新加载collectionview并将焦点集中在特定的单元格上。如果设置了collectionView.remembersLastFocusedIndexPath = true,则会调用indexPathForPreferredFocusedView委托方法。但它会记住属性名称中所说的最后一个聚焦indexPath。这不是我想要的。苹果文档令人困惑。

尝试一下:

  1. 实现委托方法:

    func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? {
    return IndexPath(item: 5, section: 0)
    }
    
  2. 强制更新焦点[例如:通过按钮操作]:

    collectionView.setNeedsFocusUpdate()
    collectionView.updateFocusIfNeeded()
    

这将强制collectionView调用indexPathForPreferredFocusedView方法。我们不必将remembersLastFocusedIndexPath设置为true。

  

注意:我的屏幕上有多个collectionViews,并且执行了上述步骤   仅在当前关注的collectionView和   我们强迫焦点更新的collectionView是相同的。

使用preferredFocusEnvironments返回首选集合视图,使其在加载视图时成为焦点(例如)。

override var preferredFocusEnvironments: [UIFocusEnvironment] {
    return [collectionView2]
}

答案 2 :(得分:1)

您应将remembersLastFocusedIndexPath设置为true

collectionView.remembersLastFocusedIndexPath = true

答案 3 :(得分:0)

根据我的尝试,仅在indexPathForPreferredFocusedView设置为true时才调用collectionView.remembersLastFocusedIndexPath

此外,当再次重新加载collectionView以获取首选的Focus时。

使用preferredFocusEnvironments也是一个很好的解决方案,但是它有其缺点。 如果您的ViewController只有collectionView,那么使用它是很好的。如果ViewController中有多个焦点项目,则焦点行为将有所不同。

答案 4 :(得分:0)

三件事解决了我面临的相同问题。

  1. self.restoreFocusAfterTransition = false

  2. func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> 
        IndexPath? {
            return IndexPath(item: 3, section: 0)
        }
    
  3. override var preferredFocusEnvironments : [UIFocusEnvironment] {
            //return collectionView in order for indexPathForPreferredFocusedView method to be called.
        return [collectionView]
    }
    

我在两个不同的视图控制器中有两个集合视图。我将UICollectionView子类化,并正在执行从一个视图控制器到另一个视图控制器的转换。

答案 5 :(得分:0)

我也遇到了这个问题。

要修复它:

  1. collectionView.remembersLastFocusedIndexPath = true

reloadData()之后:

  1. collectionView.setNeedsFocusUpdate() collectionView.updateFocusIfNeeded()

迫使它集中在最后一个集中的项目上。