indexPathForPreferredFocusedView не вызывается
Мне нужно указать, какая ячейка должна получить фокус.
Согласно документации Apple, indexPathForPreferredFocusedView
метод делегата должен быть вызван, если remembersLastFocusedIndexPath
свойство false
или, если нет сохраненного пути индекса, потому что ни одна ячейка не была ранее сфокусирована.
В моем случае я использую представление коллекции в UIViewController
и настройка remembersLastFocusedIndexPath
в false
но indexPathForPreferredFocusedView
не вызывается.
Как объяснить это поведение?
4 ответа
Вы должны установить remembersLastFocusedIndexPath
к true
.
collectionView.remembersLastFocusedIndexPath = true
Функция indexPathForPreferredFocusedView
является частью UICollectionViewDelegate, поэтому может случиться так, что делегат не был назначен вашему collectionView.
Или проблема также может быть в среде фокусировки, не принимая во внимание ваш UICollectionView.
Для справки, здесь у вас есть пример простого collectionView с 5 ячейками, в котором по умолчанию изначально выбрана ячейка в центре
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)
}
}
Свифт 4: У меня была такая же проблема. Я хотел перезагрузить collectionview
и сосредоточиться на конкретной клетке. Если я установлю collectionView.remembersLastFocusedIndexPath = true
, indexPathForPreferredFocusedView
Метод делегата вызывается. Но он будет помнить последний сфокусированный indexPath, как говорит имя свойства. Это не то, что я хотел. Документы Apple сбивают с толку.
Попробуй это:
Реализуйте метод делегата:
func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? { return IndexPath(item: 5, section: 0) }
Принудительно обновить фокус [например: в действии кнопки]:
collectionView.setNeedsFocusUpdate() collectionView.updateFocusIfNeeded()
Это заставит collectionView вызвать indexPathForPreferredFocusedView
метод. Нам не нужно устанавливать remembersLastFocusedIndexPath
к истине.
NB. У меня на экране было несколько collectionViews, и описанные выше шаги будут работать только в том случае, если в данный момент сосредоточенный collectionView и collectionView, который мы принудительно обновляем, совпадают.
Использовать preferredFocusEnvironments
вернуть предпочтительный вид коллекции, который будет в фокусе, когда представление загружается [например].
override var preferredFocusEnvironments: [UIFocusEnvironment] {
return [collectionView2]
}
У меня тоже была эта проблема.
Починить это:
collectionView.remembersLastFocusedIndexPath = true
И после reloadData()
:
collectionView.setNeedsFocusUpdate() collectionView.updateFocusIfNeeded()
Чтобы заставить его сфокусироваться на последнем фокусированном элементе.
Три вещи, которые решили ту же проблему, с которой я столкнулся.
self.restoreFocusAfterTransition = false
func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? { return IndexPath(item: 3, section: 0) }
override var preferredFocusEnvironments : [UIFocusEnvironment] { //return collectionView in order for indexPathForPreferredFocusedView method to be called. return [collectionView] }
У меня было два представления коллекции в двух разных контроллерах представления. Я создал подкласс UICollectionView и выполнял переход от одного контроллера представления к другому.
Из того, что я пытался, indexPathForPreferredFocusedView
вызывается только когда collectionView.remembersLastFocusedIndexPath
установлен в true.
Кроме того, когда collectionView
перезагрузится снова, чтобы получить предпочтительный фокус.
С помощью preferredFocusEnvironments
тоже хорошее решение, но у него есть свои минусы. Если твой ViewController
только имея collectionView
тогда это хорошо для использования. Если в пределах ViewController
Поведение фокуса будет другим.