From 2adc595f5d6cb152a47f0e8f405cce9cbd33ea57 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 8 Aug 2018 14:41:36 -0700 Subject: [PATCH] animate the position of headerBackground between scene transitions --- src/views/Header/Header.js | 37 ++++++++++++++++++--- src/views/Header/HeaderStyleInterpolator.js | 22 ++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/views/Header/Header.js b/src/views/Header/Header.js index 652700b..b3ddb22 100644 --- a/src/views/Header/Header.js +++ b/src/views/Header/Header.js @@ -80,6 +80,7 @@ class Header extends React.PureComponent { titleFromLeftInterpolator: HeaderStyleInterpolator.forCenterFromLeft, titleInterpolator: HeaderStyleInterpolator.forCenter, rightInterpolator: HeaderStyleInterpolator.forRight, + backgroundInterpolator: HeaderStyleInterpolator.forBackground, }; static get HEIGHT() { @@ -338,6 +339,29 @@ class Header extends React.PureComponent { ); } + _renderBackground(props) { + const { + index, + key, + descriptor: { options }, + } = props.scene; + + const offset = this.props.navigation.state.index - index; + + if (Math.abs(offset) > 2) { + // Scene is far away from the active scene. Hides it to avoid unnecessary + // rendering. + return null; + } + + return this._renderSubView( + { ...props, style: StyleSheet.absoluteFill }, + 'background', + () => options.headerBackground, + this.props.backgroundInterpolator + ); + } + _renderModularSubView( props, name, @@ -492,6 +516,7 @@ class Header extends React.PureComponent { render() { let appBar; + let background; const { mode, scene, isLandscape } = this.props; if (mode === 'float') { @@ -505,12 +530,16 @@ class Header extends React.PureComponent { scene, })); appBar = scenesProps.map(this._renderHeader, this); + background = scenesProps.map(this._renderBackground, this); } else { - appBar = this._renderHeader({ + const headerProps = { position: new Animated.Value(this.props.scene.index), progress: new Animated.Value(0), scene: this.props.scene, - }); + }; + + appBar = this._renderHeader(headerProps); + background = this._renderBackground(headerProps); } const { options } = scene.descriptor; @@ -590,9 +619,7 @@ class Header extends React.PureComponent { ]} > - - {options.headerBackground} - + {background} {appBar} diff --git a/src/views/Header/HeaderStyleInterpolator.js b/src/views/Header/HeaderStyleInterpolator.js index 76d1bce..32445a0 100644 --- a/src/views/Header/HeaderStyleInterpolator.js +++ b/src/views/Header/HeaderStyleInterpolator.js @@ -325,6 +325,27 @@ function forCenterFromLeft(props) { }; } +const BACKGROUND_OFFSET = Dimensions.get('window').width; +function forBackground(props) { + const { position, scene, scenes } = props; + const interpolate = getSceneIndicesForInterpolationInputRange(props); + if (!interpolate) return { opacity: 0 }; + const { first, last } = interpolate; + const index = scene.index; + const offset = BACKGROUND_OFFSET; + const outputRange = [offset, 0, -offset]; + return { + transform: [ + { + translateX: position.interpolate({ + inputRange: [first, index, last], + outputRange: I18nManager.isRTL ? outputRange.reverse() : outputRange, + }), + }, + ], + }; +} + export default { forLayout, forLeft, @@ -333,4 +354,5 @@ export default { forCenterFromLeft, forCenter, forRight, + forBackground, };