-
Notifications
You must be signed in to change notification settings - Fork 24.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TabBarIOS (Tabs) in AppleTV flickering when switching between tabs #15081
Comments
cc @dlowder-salesforce |
Thanks for the bug report, I'll take a look.... might be a race condition between the native focus engine calls and JS |
@rada While I'm working on this, I have a suggested code change that seems to remove most of the flickering. _setTab(key) {
return () => {
if(this.state.activeTab !== key) {
console.log('Selecting tab: ', key);
this.setState({ activeTab: key });
}
};
} |
@dlowder-salesforce thanks, the switching indeed improves by the condition however in case we have a more complex component, the tabs still flicker. Let me know if you need an example with such component. |
@rada I have a fix, please feel free to try it out and let me know. |
@dlowder-salesforce thanks, this fix works in case the component in the selected tab already finished rendering. However it's not working if we switch tab while the tab is not fully rendered yet. We are developing an application for AppleTV and once the first tab is shown, we fetch data from GraphQL server and display it in a ListView. The problem is that if we switch tabs during ListView rendering (renderRow), the tabs are again flickering and jumping around. I have updated the example at https://gitlab.com/radamich/tvTabBar and added a listView in the first tab and also timeout in componentDidMount. After 3 seconds, the listView is updated and is rendering 2000 rows (just for testing purposes so there's time to switch tabs, we don't have this amount of data in our app). Steps to reproduce:
Scenario 2:
Let me know if you need any more information. Thanks. List.js /**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
Text,
View,
ListView,
} from 'react-native';
export default class List extends Component {
constructor(props) {
super(props);
this.ds = new ListView.DataSource({ rowHasChanged: (r1: Object, r2: Object) => { return r1 !== r2; } });
this.state = {
dataSource: this.ds.cloneWithRows([{ value: 1 }]),
}
};
_renderRow(rowData) {
console.log('RenderRow: ', rowData.value);
return (
<View>
<Text>{rowData.value}</Text>
</View>
)
}
componentDidMount() {
setTimeout(() => {
const data = Array.from({ length: 2000 }).map((_, index) => {
return { value: index };
})
this.setState({
dataSource: this.ds.cloneWithRows(data),
})
}, 3000)
}
render() {
return (
<View>
<ListView
dataSource={this.state.dataSource}
enableEmptySections
removeClippedSubviews={false}
renderRow={this._renderRow}
/>
</View>
);
}
} index.ios.js/index.tvos.js /**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
TabBarIOS,
ListView,
} from 'react-native';
import List from './List';
export default class tvTabBar extends Component {
_tabItems: Array<{ key: string }> = [
{ key: 'TAB 1' },
{ key: 'TAB 2' },
{ key: 'TAB 3' },
{ key: 'TAB 4' },
];
constructor(props) {
super(props);
this.state = { activeTab: 'TAB 1' };
}
_getTabItem = (key: string) => {
switch (key) {
case 'TAB 1':
return (
<View style={{ flex: 1, top: 140, borderColor: 'red', borderWidth: 10 }}>
<List />
<Text style={{ fontSize: 30 }}>TAB 1</Text>
</View>
);
case 'TAB 2':
return (
<View style={{ flex: 1, top: 140, borderColor: 'green', borderWidth: 20 }}>
<Text style={{ fontSize: 30 }}>TAB 2</Text>
</View>
);
case 'TAB 3':
return (
<View style={{ flex: 1, top: 140, borderColor: 'darkblue', borderWidth: 30 }}>
<Text style={{ fontSize: 30 }}>TAB 3</Text>
</View>
);
case 'TAB 4':
return (
<View style={{ flex: 1, top: 140, borderColor: 'deeppink', borderWidth: 40 }}>
<Text style={{ fontSize: 30 }}>TAB 4</Text>
</View>
);
default:
return null;
}
}
_setTab(key) {
return () => {
console.log('Selecting tab: ', key);
this.setState({ activeTab: key });
};
}
render() {
return (
<TabBarIOS>
{
this._tabItems.map((tabItem) => {
return (
<TabBarIOS.Item
key={tabItem.key}
onPress={this._setTab(tabItem.key)}
title={tabItem.key}
selected={tabItem.key === this.state.activeTab}
>
{ this._getTabItem(tabItem.key) }
</TabBarIOS.Item>
);
})
}
</TabBarIOS>
);
}
}
AppRegistry.registerComponent('tvTabBar', () => { return tvTabBar; }); |
@rada that's very interesting, I will try that out. I take it that this problem does not occur in iOS? |
@rada I tried out your test case.... With my fix, I was still able to reproduce scenario 1 some of the time, but not scenario 2. It seems to me that when the 2000 rows show up, the entire app (including the tab bar) is rerendered, not just the tab with the list view. I'll see if I can figure out a way to prevent that. |
@dlowder-salesforce in iOS, tabBar is working fine, we don't see this problem. |
@rada please try out https://github.com/dlowder-salesforce/react-native/tree/tvos-tabbar-fix -- I think this should fix the remaining issues. I tried it with your ListView example code above and it seems to be behaving correctly. |
@dlowder-salesforce Using "react-native": "git+https://github.com/dlowder-salesforce/react-native.git#tvos-tabbar-fix", |
…er (fix facebook#15081)" This reverts commit 0e7375a.
…er (fix facebook#15081)" This reverts commit 0e7375a.
Is this a bug report?
Yes
Have you read the Bugs section of the Contributing to React Native Guide?
Yes
Environment
react-native -v
: 0.46.1node -v
: 6.5.0npm -v
: 3.10.3yarn --version
(if you use Yarn):Then, specify:
Steps to Reproduce
Expected Behavior
The switch to any tab is smooth and without any flickering or selection falling back to previous tab.
Actual Behavior
Switching between TabBarIOS.Items is flickering and is not smooth. While selecting the new tab, It seems like first the new tab is selected, then immediately the old one and then again the new tab. This results in tab flickering when switching between the tabs. Worse case is, when the tabs render some more complex composed element. In this case, the new tab is not being selected, as the render is taking longer. Once it is rendered, we can select it but again the flickering occurs.
It looks like by the time the JS processes the received native event (tab switch) and sends an event (prop) back to Native, the tab selection falls back to the previous tab.
I have included very basic TabBar example with plain view and one text where flickering occurs. However, given the simple View is used in tabs here, switching is occasionally smooth.
Reproducible Demo
link to project in gitlab: https://gitlab.com/radamich/tvTabBar
The text was updated successfully, but these errors were encountered: