mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-10 17:23:42 +08:00
Pop to top on TabNavigator when tapping already focused tab icon (#3589)
* Pop to top when tapping the tab icon for an already focused tab * Dispatch popToTop with key to scope the action properly * Add test for POP_TO_TOP with key
This commit is contained in:
@@ -57,6 +57,7 @@ const pop = createAction(POP, payload => ({
|
||||
const popToTop = createAction(POP_TO_TOP, payload => ({
|
||||
type: POP_TO_TOP,
|
||||
immediate: payload && payload.immediate,
|
||||
key: payload && payload.key,
|
||||
}));
|
||||
|
||||
const push = createAction(PUSH, payload => {
|
||||
|
||||
@@ -305,6 +305,12 @@ export default (routeConfigs, stackConfig = {}) => {
|
||||
|
||||
// Handle pop-to-top behavior. Make sure this happens after children have had a chance to handle the action, so that the inner stack pops to top first.
|
||||
if (action.type === NavigationActions.POP_TO_TOP) {
|
||||
// Refuse to handle pop to top if a key is given that doesn't correspond
|
||||
// to this router
|
||||
if (action.key && state.key !== action.key) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// If we're already at the top, then we return the state with a new
|
||||
// identity so that the action is handled by this router.
|
||||
if (state.index === 0) {
|
||||
|
||||
@@ -457,6 +457,35 @@ describe('StackRouter', () => {
|
||||
expect(state3 && state3.routes[1].index).toEqual(0);
|
||||
});
|
||||
|
||||
test('popToTop targets StackRouter by key if specified', () => {
|
||||
const ChildNavigator = () => <div />;
|
||||
ChildNavigator.router = StackRouter({
|
||||
Baz: { screen: () => <div /> },
|
||||
Qux: { screen: () => <div /> },
|
||||
});
|
||||
const router = StackRouter({
|
||||
Foo: { screen: () => <div /> },
|
||||
Bar: { screen: ChildNavigator },
|
||||
});
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction(
|
||||
{
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'Bar',
|
||||
},
|
||||
state
|
||||
);
|
||||
const barKey = state2.routes[1].routes[0].key;
|
||||
const state3 = router.getStateForAction(
|
||||
{
|
||||
type: NavigationActions.POP_TO_TOP,
|
||||
key: state2.key,
|
||||
},
|
||||
state2
|
||||
);
|
||||
expect(state3 && state3.index).toEqual(0);
|
||||
});
|
||||
|
||||
test('popToTop works as expected', () => {
|
||||
const TestRouter = StackRouter({
|
||||
foo: { screen: () => <div /> },
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import withOrientation from '../withOrientation';
|
||||
|
||||
const majorVersion = parseInt(Platform.Version, 10);
|
||||
@@ -176,6 +177,24 @@ class TabBarBottom extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_handleTabPress = index => {
|
||||
const { jumpToIndex, navigation } = this.props;
|
||||
const currentIndex = navigation.state.index;
|
||||
|
||||
if (currentIndex === index) {
|
||||
let childRoute = navigation.state.routes[index];
|
||||
if (childRoute.hasOwnProperty('index') && childRoute.index > 0) {
|
||||
navigation.dispatch(
|
||||
NavigationActions.popToTop({ key: childRoute.key })
|
||||
);
|
||||
} else {
|
||||
// TODO: do something to scroll to top
|
||||
}
|
||||
} else {
|
||||
jumpToIndex(index);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
position,
|
||||
@@ -235,8 +254,13 @@ class TabBarBottom extends React.PureComponent {
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onPress={() =>
|
||||
onPress
|
||||
? onPress({ previousScene, scene, jumpToIndex })
|
||||
: jumpToIndex(index)
|
||||
? onPress({
|
||||
previousScene,
|
||||
scene,
|
||||
jumpToIndex,
|
||||
defaultHandler: this._handleTabPress,
|
||||
})
|
||||
: this._handleTabPress(index)
|
||||
}
|
||||
>
|
||||
<Animated.View style={[styles.tab, { backgroundColor }]}>
|
||||
|
||||
@@ -91,7 +91,15 @@ export default class TabBarTop extends React.PureComponent {
|
||||
const onPress = getOnPress(previousScene, scene);
|
||||
|
||||
if (onPress) {
|
||||
onPress({ previousScene, scene, jumpToIndex });
|
||||
// To maintain the same API as `TabbarBottom`, we pass in a `defaultHandler`
|
||||
// even though I don't believe in this case it should be any different
|
||||
// than `jumpToIndex`.
|
||||
onPress({
|
||||
previousScene,
|
||||
scene,
|
||||
jumpToIndex,
|
||||
defaultHandler: jumpToIndex,
|
||||
});
|
||||
} else {
|
||||
jumpToIndex(scene.index);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user