How to force focus shift to specific UICollectionViewCell from another UICollectionViewCell

I have a UIViewController with a UICollectionView of "reviews." The user can select any review to be taken to a full-screen view with a collection view (populated by identical information) that the user can then scroll through.


What I am trying to do is focus on the UICollectionViewCell (when they return from the full-screen view) that corresponds to the LAST review that the user saw in the full screen view.


E.G

View 1 (Collection View) --> View 2 (Full screen Collection View, paginated) --> View 1 (focused cell should reflect cell from view 2)

-select review (cell) 1 -scroll to review (cell) 3 -review (cell) 3 should be focused


When the user returns from the View 2, I save the indexPath of the review cell and call scrollToItemAtIndexPath: atScrollPosition: animated:. But, this doesn't actually focus the cell, it simply shifts the UICollectionView so that the targeted cell is at the "atScrollPosition"


I am overriding the func preferredFocusView: UIView { get { return self.preferredFocusViewTest }} so that I can manually set different views as the "preferredFocusView" and I was wondering how I would be able to set a specific UICollectionViewCell as the preferredFocusView.


Currently, once returning to View 1, I am calling:

self.testCollectionView.scrollToItemAtIndexPath(NSIndexPath(forRow: index, inSection: 0), atScrollPosition: .Left, animated: false)

self.preferredFocusViewTest = self.testCollectionView

self.setNeedsFocusUpdate()

self.updateFocusIfNeeded()


To force a focus update immediately, but focus never changes from the original (in the above example, review 1). I am able to scroll and then shift focus manually to a test button for example, but cannot change focus in the collection view.


Thank you!

I understand that the focus engine only pays attention to "non-hidden views with non-zero alphas that have at least one pixel within the screen bounds" which is why I am scrolling first and then requesting and forcing an update.


http://www.slideshare.net/EvanMaloney/tvos-the-focus-engine-and-swift

I believe I may have found a workaround - I can call self.collectionViewTest.scrollToItemAtIndexPath(NSIndexPath(forRow: index, inSection: 0), atScrollPosition: .Left, animated: false)


Then set the preferredFocusViewTest = self.collectionViewTest.cellForItemAtIndexPath(NSIndexPath(forRow: index, inSection: 0)) after a delay to ensure that the correct cell is now visible.


And then finally call self.setNeedsFocusUpdate() & self.updateFocusIfNeeded()


What happens then is that it'll return to View 1, scroll to the correct indexpath, and then focus the cell.

Do you need to call both self.setNeedsFocusUpdate() & self.updateFocusIfNeeded()?


I thought that setNeedsFocusUpdate will update focus at some point soon in the future and updateFocusIfNeeded() does it right away before returning from the call. Just wondering if you need the double hit or if just updateFocusIfNeeded does it all.

Calling -setNeedsFocusUpdate will defer the update until the next run loop and should be sufficient in most cases.

You can solve this by overriding indexPathForPreferredFocusedView of UICollectionView:

func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? {
    return self.focusedIndex
  }

and then you can change the focus with this custom method as an example:

func moveFocus(toIndex: Int) {
    if 0 <= toIndex && toIndex < data.count {
      self.focusedIndex = IndexPath(row: toIndex, section: 0)
      self.collectionView.setNeedsFocusUpdate()
      self.collectionView.updateFocusIfNeeded()
    }
  }

note that collectionView.remembersLastFocusedIndexPath should be false

How to force focus shift to specific UICollectionViewCell from another UICollectionViewCell
 
 
Q