Skip to content

Commit aa8d982

Browse files
committed
merged PRs i6mi6#57 and i6mi6#70
1 parent 85f0a35 commit aa8d982

File tree

2 files changed

+105
-93
lines changed

2 files changed

+105
-93
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ The `ParallaxScrollView` component adds a few additional properties, as describe
8181
| `renderStickyHeader` | `func` | No | This renders an optional sticky header that will stick to the top of view when parallax header scrolls up. |
8282
| `stickyHeaderHeight` | `number` | If `renderStickyHeader` is used | If `renderStickyHeader` is set, then its height must be specified. |
8383
| `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)) |
84+
| `scrollingStickyHeader` | `bool` | No | This causes the sticky header to scroll into view. If set to false the sticky header will only fade in. |
8485

8586
## Latest changes
8687

Diff for: src/index.js

+104-93
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
22
import {
33
Animated,
44
Dimensions,
5+
Platform,
56
ScrollView,
67
View,
78
ViewPropTypes,
@@ -45,6 +46,7 @@ const IPropTypes = {
4546
renderStickyHeader: func,
4647
stickyHeaderHeight: number,
4748
contentContainerStyle: ViewPropTypes.style,
49+
scrollingStickyHeader: bool,
4850
};
4951

5052
class ParallaxScrollView extends Component {
@@ -59,7 +61,7 @@ class ParallaxScrollView extends Component {
5961
this.state = {
6062
scrollY: new Animated.Value(0),
6163
viewHeight: window.height,
62-
viewWidth: window.width
64+
viewWidth: window.width,
6365
};
6466
this._footerComponent = { setNativeProps() {} }; // Initial stub
6567
this._footerHeight = 0;
@@ -83,19 +85,20 @@ class ParallaxScrollView extends Component {
8385
stickyHeaderHeight,
8486
style,
8587
contentContainerStyle,
88+
scrollingStickyHeader,
8689
...scrollViewProps
8790
} = this.props;
8891

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

9699
return (
97-
<View style={[style, styles.container]}
98-
onLayout={(e) => this._maybeUpdateViewDimensions(e)}>
100+
<View style={[style, styles.container]}
101+
onLayout={(e) => this._maybeUpdateViewDimensions(e)}>
99102
{ background }
100103
{
101104
React.cloneElement(scrollElement, {
@@ -110,7 +113,7 @@ class ParallaxScrollView extends Component {
110113
)
111114
}
112115
{ maybeStickyHeader }
113-
</View>
116+
</View>
114117
);
115118
}
116119

@@ -142,8 +145,8 @@ class ParallaxScrollView extends Component {
142145
parallaxHeaderHeight,
143146
stickyHeaderHeight,
144147
onChangeHeaderVisibility,
145-
onScroll: prevOnScroll = () => {}
146-
} = this.props;
148+
onScroll: prevOnScroll = () => {},
149+
} = this.props;
147150

148151
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
149152

@@ -177,70 +180,74 @@ class ParallaxScrollView extends Component {
177180
if (width !== this.state.viewWidth || height !== this.state.viewHeight) {
178181
this.setState({
179182
viewWidth: width,
180-
viewHeight: height
183+
viewHeight: height,
181184
});
182185
}
183186
}
184187

185188
_renderBackground({ fadeOutBackground, backgroundScrollSpeed, backgroundColor, parallaxHeaderHeight, stickyHeaderHeight, renderBackground }) {
186189
const { viewWidth, viewHeight, scrollY } = this.state;
187190
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
191+
const transform = [{
192+
translateY: interpolate(scrollY, {
193+
inputRange: [0, p],
194+
outputRange: [0, -(p / backgroundScrollSpeed)],
195+
extrapolateRight: 'extend',
196+
extrapolateLeft: 'clamp',
197+
}),
198+
}];
199+
if (Platform.OS === 'ios') {
200+
transform.push({
201+
scale: interpolate(scrollY, {
202+
inputRange: [-viewHeight, 0],
203+
outputRange: [5, 1],
204+
extrapolate: 'clamp',
205+
}),
206+
});
207+
}
188208
return (
189-
<Animated.View
190-
style={[styles.backgroundImage, {
191-
backgroundColor: backgroundColor,
192-
height: parallaxHeaderHeight,
193-
width: viewWidth,
194-
opacity: fadeOutBackground
195-
? interpolate(scrollY, {
196-
inputRange: [0, p * (1/2), p * (3/4), p],
197-
outputRange: [1, 0.3, 0.1, 0],
198-
extrapolate: 'clamp'
199-
})
200-
: 1,
201-
transform: [{
202-
translateY: interpolate(scrollY, {
203-
inputRange: [0, p],
204-
outputRange: [0, -(p / backgroundScrollSpeed)],
205-
extrapolateRight: 'extend',
206-
extrapolateLeft: 'clamp'
207-
})
208-
}, {
209-
scale: interpolate(scrollY, {
210-
inputRange: [-viewHeight, 0],
211-
outputRange: [5, 1],
212-
extrapolate: 'clamp'
213-
})
214-
}]
215-
}]}>
216-
<View>
209+
<Animated.View
210+
style={[styles.backgroundImage, {
211+
backgroundColor: backgroundColor,
212+
height: parallaxHeaderHeight,
213+
width: viewWidth,
214+
opacity: fadeOutBackground
215+
? interpolate(scrollY, {
216+
inputRange: [0, p * (1/2), p * (3/4), p],
217+
outputRange: [1, 0.3, 0.1, 0],
218+
extrapolate: 'clamp',
219+
})
220+
: 1,
221+
transform,
222+
}]}>
223+
<View>
217224
{ renderBackground() }
218-
</View>
219-
</Animated.View>
225+
</View>
226+
</Animated.View>
220227
);
221228
}
222229

223230
_renderForeground({ fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, renderForeground }) {
224231
const { scrollY } = this.state;
225232
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
226233
return (
227-
<View style={styles.parallaxHeaderContainer}>
228-
<Animated.View
229-
style={[styles.parallaxHeader, {
230-
height: parallaxHeaderHeight,
231-
opacity: fadeOutForeground
232-
? interpolate(scrollY, {
233-
inputRange: [0, p * (1/2), p * (3/4), p],
234-
outputRange: [1, 0.3, 0.1, 0],
235-
extrapolate: 'clamp'
236-
})
237-
: 1
238-
}]}>
239-
<View style={{ height: parallaxHeaderHeight }}>
240-
{ renderForeground() }
234+
<View style={styles.parallaxHeaderContainer}>
235+
<Animated.View
236+
style={[styles.parallaxHeader, {
237+
height: parallaxHeaderHeight,
238+
opacity: fadeOutForeground
239+
? interpolate(scrollY, {
240+
inputRange: [0, p * (1/2), p * (3/4), p],
241+
outputRange: [1, 0.3, 0.1, 0],
242+
extrapolate: 'clamp',
243+
})
244+
: 1,
245+
}]}>
246+
<View style={{ height: parallaxHeaderHeight }}>
247+
{ renderForeground() }
248+
</View>
249+
</Animated.View>
241250
</View>
242-
</Animated.View>
243-
</View>
244251
);
245252
}
246253

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

254261
return (
255-
<View
256-
style={containerStyles}
257-
onLayout={e => {
258-
// Adjust the bottom height so we can scroll the parallax header all the way up.
259-
const { nativeEvent: { layout: { height } } } = e;
260-
const footerHeight = Math.max(0, viewHeight - height - stickyHeaderHeight);
261-
if (this._footerHeight !== footerHeight) {
262-
this._footerComponent.setNativeProps({ style: { height: footerHeight }});
263-
this._footerHeight = footerHeight;
264-
}
265-
}}>
262+
<View
263+
style={containerStyles}
264+
onLayout={e => {
265+
// Adjust the bottom height so we can scroll the parallax header all the way up.
266+
const { nativeEvent: { layout: { height } } } = e;
267+
const footerHeight = Math.max(0, viewHeight - height - stickyHeaderHeight);
268+
if (this._footerHeight !== footerHeight) {
269+
this._footerComponent.setNativeProps({ style: { height: footerHeight }});
270+
this._footerHeight = footerHeight;
271+
}
272+
}}>
266273
{ children }
267-
</View>
268-
);
274+
</View>
275+
);
269276
}
270277

271278
_renderFooterSpacer({ contentBackgroundColor }) {
272279
return (
273-
<View ref={ref => this._footerComponent = ref } style={{ backgroundColor: contentBackgroundColor }}/>
280+
<View ref={ref => this._footerComponent = ref } style={{ backgroundColor: contentBackgroundColor }}/>
274281
);
275282
}
276283

277-
_maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader }) {
284+
_maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader, scrollingStickyHeader }) {
278285
const { viewWidth, scrollY } = this.state;
279286
if (renderStickyHeader || renderFixedHeader) {
280287
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
@@ -283,39 +290,42 @@ class ParallaxScrollView extends Component {
283290
outputRange: [0, stickyHeaderHeight],
284291
extrapolate: 'clamp',
285292
});
293+
const stickyHeader = scrollingStickyHeader ? (
294+
<Animated.View
295+
style={{
296+
transform: [{
297+
translateY: interpolate(scrollY, {
298+
inputRange: [0, p],
299+
outputRange: [stickyHeaderHeight, 0],
300+
extrapolate: 'clamp',
301+
}),
302+
}],
303+
}}>
304+
{this.renderStickyHeader()}
305+
</Animated.View>
306+
) : renderStickyHeader();
286307
return (
287308
<View style={[styles.stickyHeader, { width: viewWidth }]}>
288309
{
289310
renderStickyHeader
290311
? (
291-
<Animated.View
292-
style={{
293-
backgroundColor: backgroundColor,
294-
height: height,
295-
opacity: interpolate(scrollY, {
296-
inputRange: [0, p],
297-
outputRange: [0, 1],
298-
extrapolate: 'clamp'
299-
})
300-
}}>
301-
<Animated.View
302-
style={{
303-
transform: [{
304-
translateY: interpolate(scrollY, {
305-
inputRange: [0, p],
306-
outputRange: [stickyHeaderHeight, 0],
307-
extrapolate: 'clamp'
308-
})
309-
}]
312+
<Animated.View
313+
style={{
314+
backgroundColor: backgroundColor,
315+
height: height,
316+
opacity: interpolate(scrollY, {
317+
inputRange: [0, p],
318+
outputRange: [0, 1],
319+
extrapolate: 'clamp',
320+
}),
310321
}}>
311-
{ renderStickyHeader() }
312-
</Animated.View>
313-
</Animated.View>
322+
{ stickyHeader }
323+
</Animated.View>
314324
)
315325
: null
316326
}
317327
{ renderFixedHeader && renderFixedHeader() }
318-
</View>
328+
</View>
319329
);
320330
} else {
321331
return null;
@@ -336,7 +346,8 @@ ParallaxScrollView.defaultProps = {
336346
renderParallaxHeader: renderEmpty, // Deprecated (will be removed in 0.18.0)
337347
renderForeground: null,
338348
stickyHeaderHeight: 0,
339-
contentContainerStyle: null
349+
contentContainerStyle: null,
350+
scrollingStickyheader: true,
340351
};
341352

342353
module.exports = ParallaxScrollView;

0 commit comments

Comments
 (0)