I need to specify which cell should receive focus.
According to Apple Documentation the indexPathForPreferredFocusedView
delegate method should be called if the remembersLastFocusedIndexPath
property is false
, or if there is no saved index path because no cell was previously focused.
In my case I am using a collection view in a UIViewController
and setting remembersLastFocusedIndexPath
to false
but indexPathForPreferredFocusedView
is not being called.
How explain this behaviour?
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)
}
}
You should set remembersLastFocusedIndexPath
to true
.
collectionView.remembersLastFocusedIndexPath = true
Swift 4: I had the same issue. I wanted to reload collectionview
and force focus on a particluar cell. If I set collectionView.remembersLastFocusedIndexPath = true
, indexPathForPreferredFocusedView
delegate method is called. But it will remember the last focused indexPath as the property name says. This is not what I wanted. Apple docs are confusing.
Try this:
Implement the delegate method:
func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? {
return IndexPath(item: 5, section: 0)
}
Force update the focus [ex: in a button action]:
collectionView.setNeedsFocusUpdate()
collectionView.updateFocusIfNeeded()
This will force the collectionView to call the indexPathForPreferredFocusedView
method. We don't have to set the remembersLastFocusedIndexPath
to true.
NB: I had multiple collectionViews in my screen and the above steps will work only if the currently focused collectionView and the collectionView which we are forcing the focus update are same.
Use the preferredFocusEnvironments
to return the preferred collectionview to be in focus when the view loads [for example].
override var preferredFocusEnvironments: [UIFocusEnvironment] {
return [collectionView2]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With