Browse Source

tvOS: Fixed bug when restoring the focused cell in the server browsing view

When the collection view of the server browsing view controller is appearing, it will in some cases try to reload its data. If this happens depends on the server browser implementation. Some server browsers will trigger an update (VLCMedia, Plex, UPnP and HTTP) and some won't (FTP). When this happens, all the cells in the collection view are being recycled and the view is repopulated with cells. After that, the tvOS focus engine will give focus to the collection view, which will then restore the previously selected cell. Unfortunately, this is implemented by Apple in such a way that the focus engine will pass the cell to select to the UICollectionView class, which will then select the same cell again. The problem here is that the cell recycling mechanism does not guarantee that the same cell is used for the same thing. This usually leads to the selection of the wrong cell when the view comes back into the foreground and an update was triggered.

I my opinion, this is an Apple bug. The UICollectionView class should be able to select the correct cell after its data has been reloaded. But since this is the current situation, we need to work around the problem to fix the issue. One way to do this would be to do the same thing as the FTP server browser and not update when the view reappears. However, this decreases flexibility and causes a dependency of the the server browsers on UI problems.

Another way to solve this is to use the tvOS focus engine. The idea is to select the correct cell ourselves whenever the collection view is gaining focus. In addition, we prevent the wrong selection of the cell that the UICollectionView class wants to select by telling the focus engine that only the cell we want to switch to is focusable during the time when the collection view gains focus. This commit implements that approach.

Signed-off-by: Felix Paul Kühne <fkuehne@videolan.org>
Benjamin Adolphi 9 years ago
parent
commit
af3c735d81
1 changed files with 28 additions and 0 deletions
  1. 28 0
      Apple-TV/VLCServerBrowsingTVViewController.m

+ 28 - 0
Apple-TV/VLCServerBrowsingTVViewController.m

@@ -19,6 +19,8 @@
 @interface VLCServerBrowsingTVViewController ()
 {
     UILabel *_nothingFoundLabel;
+    NSIndexPath *_currentFocus;
+    BOOL _focusChangeAllowed;
 }
 @property (nonatomic, readonly) id<VLCNetworkServerBrowser>serverBrowser;
 @property (nonatomic) VLCServerBrowsingController *browsingController;
@@ -38,6 +40,9 @@
         self.title = serverBrowser.title;
 
         self.downloadArtwork = [[NSUserDefaults standardUserDefaults] boolForKey:kVLCSettingDownloadArtwork];
+
+        _currentFocus = [NSIndexPath indexPathForRow:0 inSection:0];
+        _focusChangeAllowed = YES;
     }
     return self;
 }
@@ -156,4 +161,27 @@
     [self didSelectItem:item index:row singlePlayback:singlePlayback];
 }
 
+#pragma mark - focus recovery workaround
+
+- (void)collectionView:(UICollectionView *)collectionView didUpdateFocusInContext:(UICollectionViewFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
+{
+    if (context.previouslyFocusedIndexPath == nil && context.nextFocusedIndexPath != nil)
+        [self setNeedsFocusUpdate];
+
+    if (context.previouslyFocusedIndexPath != nil && context.nextFocusedIndexPath != nil)
+        _currentFocus = context.nextFocusedIndexPath;
+
+    _focusChangeAllowed = context.nextFocusedIndexPath != nil;
+}
+
+- (BOOL)collectionView:(UICollectionView *)collectionView canFocusItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    return _focusChangeAllowed || [_currentFocus compare:indexPath] == NSOrderedSame;
+}
+
+- (NSIndexPath *)indexPathForPreferredFocusedViewInCollectionView:(UICollectionView *)collectionView
+{
+    return _currentFocus;
+}
+
 @end