Permalink
Browse files

Apple TV: RCTTabBar selection controlled by native after render (fix #…

…15081)

Summary:
**Motivation**

Fix flickering in TabBarIOS on Apple TV... issue #15081

After this change, on Apple TV, TabBarIOS item selections will be controlled purely from the native side after initial render with the `selected` prop.  This is necessary because the `UITabBar` implementation in tvOS moves the selection before calling `shouldSelectViewController:`; this issue does not occur on iOS.

**Test plan**

Existing CI should still pass. Issue is resolved when testing the example code in #15081 .
Closes #15220

Differential Revision: D5601671

Pulled By: javache

fbshipit-source-id: c18e7d3482d6c07d534ff40a443a6f642d4267bb
  • Loading branch information...
dlowder-salesforce authored and facebook-github-bot committed Aug 10, 2017
1 parent 3a031cc commit 0e7375ae3656b54d4fb52a657db0d1ad1455bcba
Showing with 43 additions and 0 deletions.
  1. +22 −0 React/Views/RCTTabBar.m
  2. +4 −0 React/Views/RCTTabBarItem.h
  3. +15 −0 React/Views/RCTTabBarItem.m
  4. +2 −0 docs/BuildingForAppleTV.md
View
@@ -115,9 +115,17 @@ - (void)reactBridgeDidFinishTransaction
[tab.barItem setTitleTextAttributes:@{NSForegroundColorAttributeName: self.tintColor} forState:UIControlStateSelected];
controller.tabBarItem = tab.barItem;
#if TARGET_OS_TV
// On Apple TV, disable JS control of selection after initial render
if (tab.selected && !tab.wasSelectedInJS) {
self->_tabController.selectedViewController = controller;
}
tab.wasSelectedInJS = YES;
#else
if (tab.selected) {
self->_tabController.selectedViewController = controller;
}
#endif
}];
}
@@ -175,6 +183,18 @@ - (void)setItemPositioning:(UITabBarItemPositioning)itemPositioning
#pragma mark - UITabBarControllerDelegate
#if TARGET_OS_TV
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(nonnull UIViewController *)viewController
{
NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
RCTTabBarItem *tab = (RCTTabBarItem *)self.reactSubviews[index];
if (tab.onPress) tab.onPress(nil);
return;
}
#else
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
@@ -183,6 +203,8 @@ - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectView
return NO;
}
#endif
#if TARGET_OS_TV
- (BOOL)isUserInteractionEnabled
@@ -29,4 +29,8 @@
@property (nonatomic, readonly) UITabBarItem *barItem;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
#if TARGET_OS_TV
@property (nonatomic, assign) BOOL wasSelectedInJS;
#endif
@end
@@ -42,6 +42,9 @@ - (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
_systemIcon = NSNotFound;
#if TARGET_OS_TV
_wasSelectedInJS = NO;
#endif
}
return self;
}
@@ -118,4 +121,16 @@ - (UIViewController *)reactViewController
return self.superview.reactViewController;
}
#if TARGET_OS_TV
// On Apple TV, we let native control the tab bar selection after initial render
- (void)setSelected:(BOOL)selected
{
if (!_wasSelectedInJS) {
_selected = selected;
}
}
#endif
@end
@@ -89,6 +89,8 @@ class Game2048 extends React.Component {
- *Back navigation with the TV remote menu button*: The `BackHandler` component, originally written to support the Android back button, now also supports back navigation on the Apple TV using the menu button on the TV remote.
- *TabBarIOS behavior*: The `TabBarIOS` component wraps the native `UITabBar` API, which works differently on Apple TV. To avoid jittery rerendering of the tab bar in tvOS (see [this issue](https://github.com/facebook/react-native/issues/15081)), the selected tab bar item can only be set from Javascript on initial render, and is controlled after that by the user through native code.
- *Known issues*:
- [ListView scrolling](https://github.com/facebook/react-native/issues/12793). The issue can be easily worked around by setting `removeClippedSubviews` to false in ListView and similar components. For more discussion of this issue, see [this PR](https://github.com/facebook/react-native/pull/12944).

0 comments on commit 0e7375a

Please sign in to comment.