Skip to content

Commit

Permalink
merged PRs i6mi6#57 and i6mi6#70
Browse files Browse the repository at this point in the history
  • Loading branch information
fungilation committed Aug 5, 2017
1 parent 85f0a35 commit aa8d982
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 93 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ The `ParallaxScrollView` component adds a few additional properties, as describe
| `renderStickyHeader` | `func` | No | This renders an optional sticky header that will stick to the top of view when parallax header scrolls up. |
| `stickyHeaderHeight` | `number` | If `renderStickyHeader` is used | If `renderStickyHeader` is set, then its height must be specified. |
| `contentContainerStyle` | `object` | No | These styles will be applied to the scroll view content container which wraps all of the child views. (same as for [ScrollView](https://facebook.github.io/react-native/docs/scrollview.html#contentcontainerstyle)) |
| `scrollingStickyHeader` | `bool` | No | This causes the sticky header to scroll into view. If set to false the sticky header will only fade in. |

## Latest changes

Expand Down
197 changes: 104 additions & 93 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Component } from 'react';
import {
Animated,
Dimensions,
Platform,
ScrollView,
View,
ViewPropTypes,
Expand Down Expand Up @@ -45,6 +46,7 @@ const IPropTypes = {
renderStickyHeader: func,
stickyHeaderHeight: number,
contentContainerStyle: ViewPropTypes.style,
scrollingStickyHeader: bool,
};

class ParallaxScrollView extends Component {
Expand All @@ -59,7 +61,7 @@ class ParallaxScrollView extends Component {
this.state = {
scrollY: new Animated.Value(0),
viewHeight: window.height,
viewWidth: window.width
viewWidth: window.width,
};
this._footerComponent = { setNativeProps() {} }; // Initial stub
this._footerHeight = 0;
Expand All @@ -83,19 +85,20 @@ class ParallaxScrollView extends Component {
stickyHeaderHeight,
style,
contentContainerStyle,
scrollingStickyHeader,
...scrollViewProps
} = this.props;

const background = this._renderBackground({ fadeOutBackground, backgroundScrollSpeed, backgroundColor, parallaxHeaderHeight, stickyHeaderHeight, renderBackground });
const foreground = this._renderForeground({ fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, renderForeground: renderForeground || renderParallaxHeader });
const bodyComponent = this._wrapChildren(children, { contentBackgroundColor, stickyHeaderHeight, contentContainerStyle });
const footerSpacer = this._renderFooterSpacer({ contentBackgroundColor });
const maybeStickyHeader = this._maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader });
const maybeStickyHeader = this._maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader, scrollingStickyHeader });
const scrollElement = renderScrollComponent(scrollViewProps);

return (
<View style={[style, styles.container]}
onLayout={(e) => this._maybeUpdateViewDimensions(e)}>
<View style={[style, styles.container]}
onLayout={(e) => this._maybeUpdateViewDimensions(e)}>
{ background }
{
React.cloneElement(scrollElement, {
Expand All @@ -110,7 +113,7 @@ class ParallaxScrollView extends Component {
)
}
{ maybeStickyHeader }
</View>
</View>
);
}

Expand Down Expand Up @@ -142,8 +145,8 @@ class ParallaxScrollView extends Component {
parallaxHeaderHeight,
stickyHeaderHeight,
onChangeHeaderVisibility,
onScroll: prevOnScroll = () => {}
} = this.props;
onScroll: prevOnScroll = () => {},
} = this.props;

const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);

Expand Down Expand Up @@ -177,70 +180,74 @@ class ParallaxScrollView extends Component {
if (width !== this.state.viewWidth || height !== this.state.viewHeight) {
this.setState({
viewWidth: width,
viewHeight: height
viewHeight: height,
});
}
}

_renderBackground({ fadeOutBackground, backgroundScrollSpeed, backgroundColor, parallaxHeaderHeight, stickyHeaderHeight, renderBackground }) {
const { viewWidth, viewHeight, scrollY } = this.state;
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
const transform = [{
translateY: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [0, -(p / backgroundScrollSpeed)],
extrapolateRight: 'extend',
extrapolateLeft: 'clamp',
}),
}];
if (Platform.OS === 'ios') {
transform.push({
scale: interpolate(scrollY, {
inputRange: [-viewHeight, 0],
outputRange: [5, 1],
extrapolate: 'clamp',
}),
});
}
return (
<Animated.View
style={[styles.backgroundImage, {
backgroundColor: backgroundColor,
height: parallaxHeaderHeight,
width: viewWidth,
opacity: fadeOutBackground
? interpolate(scrollY, {
inputRange: [0, p * (1/2), p * (3/4), p],
outputRange: [1, 0.3, 0.1, 0],
extrapolate: 'clamp'
})
: 1,
transform: [{
translateY: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [0, -(p / backgroundScrollSpeed)],
extrapolateRight: 'extend',
extrapolateLeft: 'clamp'
})
}, {
scale: interpolate(scrollY, {
inputRange: [-viewHeight, 0],
outputRange: [5, 1],
extrapolate: 'clamp'
})
}]
}]}>
<View>
<Animated.View
style={[styles.backgroundImage, {
backgroundColor: backgroundColor,
height: parallaxHeaderHeight,
width: viewWidth,
opacity: fadeOutBackground
? interpolate(scrollY, {
inputRange: [0, p * (1/2), p * (3/4), p],
outputRange: [1, 0.3, 0.1, 0],
extrapolate: 'clamp',
})
: 1,
transform,
}]}>
<View>
{ renderBackground() }
</View>
</Animated.View>
</View>
</Animated.View>
);
}

_renderForeground({ fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, renderForeground }) {
const { scrollY } = this.state;
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
return (
<View style={styles.parallaxHeaderContainer}>
<Animated.View
style={[styles.parallaxHeader, {
height: parallaxHeaderHeight,
opacity: fadeOutForeground
? interpolate(scrollY, {
inputRange: [0, p * (1/2), p * (3/4), p],
outputRange: [1, 0.3, 0.1, 0],
extrapolate: 'clamp'
})
: 1
}]}>
<View style={{ height: parallaxHeaderHeight }}>
{ renderForeground() }
<View style={styles.parallaxHeaderContainer}>
<Animated.View
style={[styles.parallaxHeader, {
height: parallaxHeaderHeight,
opacity: fadeOutForeground
? interpolate(scrollY, {
inputRange: [0, p * (1/2), p * (3/4), p],
outputRange: [1, 0.3, 0.1, 0],
extrapolate: 'clamp',
})
: 1,
}]}>
<View style={{ height: parallaxHeaderHeight }}>
{ renderForeground() }
</View>
</Animated.View>
</View>
</Animated.View>
</View>
);
}

Expand All @@ -252,29 +259,29 @@ class ParallaxScrollView extends Component {
containerStyles.push(contentContainerStyle);

return (
<View
style={containerStyles}
onLayout={e => {
// Adjust the bottom height so we can scroll the parallax header all the way up.
const { nativeEvent: { layout: { height } } } = e;
const footerHeight = Math.max(0, viewHeight - height - stickyHeaderHeight);
if (this._footerHeight !== footerHeight) {
this._footerComponent.setNativeProps({ style: { height: footerHeight }});
this._footerHeight = footerHeight;
}
}}>
<View
style={containerStyles}
onLayout={e => {
// Adjust the bottom height so we can scroll the parallax header all the way up.
const { nativeEvent: { layout: { height } } } = e;
const footerHeight = Math.max(0, viewHeight - height - stickyHeaderHeight);
if (this._footerHeight !== footerHeight) {
this._footerComponent.setNativeProps({ style: { height: footerHeight }});
this._footerHeight = footerHeight;
}
}}>
{ children }
</View>
);
</View>
);
}

_renderFooterSpacer({ contentBackgroundColor }) {
return (
<View ref={ref => this._footerComponent = ref } style={{ backgroundColor: contentBackgroundColor }}/>
<View ref={ref => this._footerComponent = ref } style={{ backgroundColor: contentBackgroundColor }}/>
);
}

_maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader }) {
_maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader, scrollingStickyHeader }) {
const { viewWidth, scrollY } = this.state;
if (renderStickyHeader || renderFixedHeader) {
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
Expand All @@ -283,39 +290,42 @@ class ParallaxScrollView extends Component {
outputRange: [0, stickyHeaderHeight],
extrapolate: 'clamp',
});
const stickyHeader = scrollingStickyHeader ? (
<Animated.View
style={{
transform: [{
translateY: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [stickyHeaderHeight, 0],
extrapolate: 'clamp',
}),
}],
}}>
{this.renderStickyHeader()}
</Animated.View>
) : renderStickyHeader();
return (
<View style={[styles.stickyHeader, { width: viewWidth }]}>
{
renderStickyHeader
? (
<Animated.View
style={{
backgroundColor: backgroundColor,
height: height,
opacity: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [0, 1],
extrapolate: 'clamp'
})
}}>
<Animated.View
style={{
transform: [{
translateY: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [stickyHeaderHeight, 0],
extrapolate: 'clamp'
})
}]
<Animated.View
style={{
backgroundColor: backgroundColor,
height: height,
opacity: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [0, 1],
extrapolate: 'clamp',
}),
}}>
{ renderStickyHeader() }
</Animated.View>
</Animated.View>
{ stickyHeader }
</Animated.View>
)
: null
}
{ renderFixedHeader && renderFixedHeader() }
</View>
</View>
);
} else {
return null;
Expand All @@ -336,7 +346,8 @@ ParallaxScrollView.defaultProps = {
renderParallaxHeader: renderEmpty, // Deprecated (will be removed in 0.18.0)
renderForeground: null,
stickyHeaderHeight: 0,
contentContainerStyle: null
contentContainerStyle: null,
scrollingStickyheader: true,
};

module.exports = ParallaxScrollView;

0 comments on commit aa8d982

Please sign in to comment.