Skip to content
This repository was archived by the owner on Feb 25, 2020. It is now read-only.

Commit 68bd0f4

Browse files
committed
fix: properly handle floating header height
Previously, the header height wasn't stored per screen. This resulted in header height always referring to the one in last mounted screen. As a result, the top margin for screens were incorrect. This resulted in bugs such as when you go to a screen with no header, header height will stay 0 even after navigating back. This commit stores the height for each screen separately, handling this properly.
1 parent 05e1f31 commit 68bd0f4

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed

src/views/Header/HeaderContainer.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
import * as React from 'react';
2-
import {
3-
View,
4-
StyleSheet,
5-
LayoutChangeEvent,
6-
StyleProp,
7-
ViewStyle,
8-
} from 'react-native';
2+
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
93
import {
104
Layout,
115
Route,
@@ -22,7 +16,7 @@ export type Props = {
2216
scenes: Array<HeaderScene<Route> | undefined>;
2317
navigation: NavigationProp;
2418
getPreviousRoute: (props: { route: Route }) => Route | undefined;
25-
onLayout?: (e: LayoutChangeEvent) => void;
19+
onContentHeightChange?: (props: { route: Route; height: number }) => void;
2620
styleInterpolator: HeaderStyleInterpolator;
2721
style?: StyleProp<ViewStyle>;
2822
};
@@ -33,7 +27,7 @@ export default function HeaderContainer({
3327
layout,
3428
navigation,
3529
getPreviousRoute,
36-
onLayout,
30+
onContentHeightChange,
3731
styleInterpolator,
3832
style,
3933
}: Props) {
@@ -91,7 +85,15 @@ export default function HeaderContainer({
9185
return (
9286
<View
9387
key={scene.route.key}
94-
onLayout={onLayout}
88+
onLayout={
89+
onContentHeightChange
90+
? e =>
91+
onContentHeightChange({
92+
route: scene.route,
93+
height: e.nativeEvent.layout.height,
94+
})
95+
: undefined
96+
}
9597
pointerEvents="box-none"
9698
accessibilityElementsHidden={!isFocused}
9799
importantForAccessibility={

src/views/Stack/Stack.tsx

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ type State = {
6060
scenes: HeaderScene<Route>[];
6161
progress: ProgressValues;
6262
layout: Layout;
63-
floatingHeaderHeight: number;
63+
floatingHeaderHeights: { [key: string]: number };
6464
};
6565

6666
const dimensions = Dimensions.get('window');
@@ -92,6 +92,23 @@ const { cond, eq } = Animated;
9292

9393
const ANIMATED_ONE = new Animated.Value(1);
9494

95+
const getFloatingHeaderHeights = (
96+
routes: Route[],
97+
layout: Layout,
98+
previous: { [key: string]: number }
99+
) => {
100+
const defaultHeaderHeight = getDefaultHeaderHeight(layout);
101+
102+
return routes.reduce(
103+
(acc, curr) => {
104+
acc[curr.key] = previous[curr.key] || defaultHeaderHeight;
105+
106+
return acc;
107+
},
108+
{} as { [key: string]: number }
109+
);
110+
};
111+
95112
export default class Stack extends React.Component<Props, State> {
96113
static getDerivedStateFromProps(props: Props, state: State) {
97114
if (
@@ -157,6 +174,11 @@ export default class Stack extends React.Component<Props, State> {
157174
}),
158175
progress,
159176
descriptors: props.descriptors,
177+
floatingHeaderHeights: getFloatingHeaderHeights(
178+
props.routes,
179+
state.layout,
180+
state.floatingHeaderHeights
181+
),
160182
};
161183
}
162184

@@ -171,7 +193,7 @@ export default class Stack extends React.Component<Props, State> {
171193
// This is not a great heuristic here. We don't know synchronously
172194
// on mount what the header height is so we have just used the most
173195
// common cases here.
174-
floatingHeaderHeight: getDefaultHeaderHeight(layout),
196+
floatingHeaderHeights: {},
175197
};
176198

177199
private handleLayout = (e: LayoutChangeEvent) => {
@@ -186,15 +208,35 @@ export default class Stack extends React.Component<Props, State> {
186208

187209
const layout = { width, height };
188210

189-
this.setState({ layout });
211+
this.setState({
212+
layout,
213+
floatingHeaderHeights: getFloatingHeaderHeights(
214+
this.props.routes,
215+
layout,
216+
{}
217+
),
218+
});
190219
};
191220

192-
private handleFloatingHeaderLayout = (e: LayoutChangeEvent) => {
193-
const { height } = e.nativeEvent.layout;
221+
private handleFloatingHeaderLayout = ({
222+
route,
223+
height,
224+
}: {
225+
route: Route;
226+
height: number;
227+
}) => {
228+
const previousHeight = this.state.floatingHeaderHeights[route.key];
194229

195-
if (height !== this.state.floatingHeaderHeight) {
196-
this.setState({ floatingHeaderHeight: height });
230+
if (previousHeight && previousHeight === height) {
231+
return;
197232
}
233+
234+
this.setState(state => ({
235+
floatingHeaderHeights: {
236+
...state.floatingHeaderHeights,
237+
[route.key]: height,
238+
},
239+
}));
198240
};
199241

200242
private handleTransitionStart = ({
@@ -238,7 +280,7 @@ export default class Stack extends React.Component<Props, State> {
238280
onGestureEnd,
239281
} = this.props;
240282

241-
const { scenes, layout, progress, floatingHeaderHeight } = this.state;
283+
const { scenes, layout, progress, floatingHeaderHeights } = this.state;
242284

243285
const focusedRoute = navigation.state.routes[navigation.state.index];
244286
const focusedOptions = descriptors[focusedRoute.key].options;
@@ -320,7 +362,7 @@ export default class Stack extends React.Component<Props, State> {
320362
onGestureCanceled={onGestureCanceled}
321363
onGestureEnd={onGestureEnd}
322364
gestureResponseDistance={gestureResponseDistance}
323-
floatingHeaderHeight={floatingHeaderHeight}
365+
floatingHeaderHeight={floatingHeaderHeights[route.key]}
324366
hasCustomHeader={header === null}
325367
getPreviousRoute={getPreviousRoute}
326368
headerMode={headerMode}
@@ -348,7 +390,7 @@ export default class Stack extends React.Component<Props, State> {
348390
scenes,
349391
navigation,
350392
getPreviousRoute,
351-
onLayout: this.handleFloatingHeaderLayout,
393+
onContentHeightChange: this.handleFloatingHeaderLayout,
352394
styleInterpolator:
353395
focusedOptions.headerStyleInterpolator !== undefined
354396
? focusedOptions.headerStyleInterpolator

0 commit comments

Comments
 (0)