diff --git a/.gitignore b/.gitignore index 64b4cb1..02c6251 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ lib/ node_modules/ npm-debug.log +.DS_Store diff --git a/README.md b/README.md index 3703ebf..6a1f359 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,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. | | `outputScaleValue` | `number` | No | The value for the scale interpolation output value, default `5` | diff --git a/examples/ListView/android/gradlew b/examples/ListView/android/gradlew old mode 100755 new mode 100644 diff --git a/examples/NestedViews/android/gradlew b/examples/NestedViews/android/gradlew old mode 100755 new mode 100644 diff --git a/package.json b/package.json index 046ddf9..850f24d 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,33 @@ { - "name": "react-native-parallax-scroll-view", - "version": "0.20.1", - "description": "A ScrollView-like component with parallax and sticky header support", - "main": "src/index.js", - "repository": { - "type": "git", - "url": "https://github.com/jaysoo/react-native-parallax-scroll-view" - }, - "files": [ - "src", - "demo.ios.gif", - "demo.android.20160117.gif", - "README.md", - "LICENSE" - ], - "keywords": [ - "react-native", - "react", - "parallax", - "scrollable", - "scrollview", - "sticky", - "react-component", - "ios", - "android" - ], - "author": "Jack Hsu", - "license": "ISC" + "name": "react-native-parallax-scroll-view", + "version": "0.20.1", + "description": "A ScrollView-like component with parallax and sticky header support", + "main": "src/index.js", + "repository": { + "type": "git", + "url": "https://github.com/jaysoo/react-native-parallax-scroll-view" + }, + "files": [ + "src", + "demo.ios.gif", + "demo.android.20160117.gif", + "README.md", + "LICENSE" + ], + "keywords": [ + "react-native", + "react", + "parallax", + "scrollable", + "scrollview", + "sticky", + "react-component", + "ios", + "android" + ], + "author": "Jack Hsu", + "license": "ISC", + "dependencies": { + "prop-types": "^15.5.10" + } } diff --git a/src/index.js b/src/index.js index a636ead..b2e5e4f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,16 @@ import React, { Component } from 'react' -import { Animated, Dimensions, ScrollView, View } from 'react-native' +import { + Animated, + Dimensions, + ScrollView, + View, + ViewPropTypes, +} from 'react-native' +import PropTypes from 'prop-types' const styles = require('./styles') -const { bool, func, number, string } = React.PropTypes +const { bool, func, number, string } = PropTypes const window = Dimensions.get('window') @@ -37,8 +44,9 @@ const IPropTypes = { renderScrollComponent: func, renderStickyHeader: func, stickyHeaderHeight: number, - contentContainerStyle: View.propTypes.style, - outputScaleValue: number + contentContainerStyle: ViewPropTypes.style, + scrollingStickyHeader: bool, + outputScaleValue: number, } class ParallaxScrollView extends Component { @@ -57,10 +65,10 @@ class ParallaxScrollView extends Component { this.state = { scrollY: new Animated.Value(0), viewHeight: window.height, - viewWidth: window.width + viewWidth: window.width, } this.scrollY = new Animated.Value(0) - this._footerComponent = { setNativeProps() {} } // Initial stub + this._footerComponent = { setNativeProps() {} } // Initial stub this._footerHeight = 0 } @@ -86,7 +94,8 @@ class ParallaxScrollView extends Component { renderStickyHeader, stickyHeaderHeight, style, - contentContainerStyle, + contentContainerStyle, + scrollingStickyHeader, outputScaleValue, ...scrollViewProps } = this.props @@ -98,18 +107,18 @@ class ParallaxScrollView extends Component { parallaxHeaderHeight, stickyHeaderHeight, renderBackground, - outputScaleValue + outputScaleValue, }) const foreground = this._renderForeground({ fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, - renderForeground: renderForeground || renderParallaxHeader + renderForeground: renderForeground || renderParallaxHeader, }) const bodyComponent = this._wrapChildren(children, { contentBackgroundColor, stickyHeaderHeight, - contentContainerStyle + contentContainerStyle, }) const footerSpacer = this._renderFooterSpacer({ contentBackgroundColor }) const maybeStickyHeader = this._maybeRenderStickyHeader({ @@ -117,7 +126,8 @@ class ParallaxScrollView extends Component { stickyHeaderHeight, backgroundColor, renderFixedHeader, - renderStickyHeader + renderStickyHeader, + scrollingStickyHeader, }) const scrollElement = renderScrollComponent(scrollViewProps) return ( @@ -136,7 +146,7 @@ class ParallaxScrollView extends Component { onScroll: Animated.event( [{ nativeEvent: { contentOffset: { y: this.scrollY } } }], { useNativeDriver: true, listener: this._onScroll.bind(this) } - ) + ), // onScroll: this._onScroll.bind(this) }, foreground, @@ -151,17 +161,14 @@ class ParallaxScrollView extends Component { /* * Expose `ScrollView` API so this component is composable with any component that expects a `ScrollView`. */ - getScrollResponder() { - return this.refs[SCROLLVIEW_REF]._component.getScrollResponder() - } getScrollableNode() { - return this.getScrollResponder().getScrollableNode() + return this.refs[SCROLLVIEW_REF].scrollResponderGetScrollableNode() } getInnerViewNode() { - return this.getScrollResponder().getInnerViewNode() + return this.refs[SCROLLVIEW_REF].getInnerViewNode() } scrollTo(...args) { - this.getScrollResponder().scrollTo(...args) + this.refs[SCROLLVIEW_REF].scrollResponderScrollTo(...args) } setNativeProps(props) { this.refs[SCROLLVIEW_REF].setNativeProps(props) @@ -176,12 +183,12 @@ class ParallaxScrollView extends Component { parallaxHeaderHeight, stickyHeaderHeight, onChangeHeaderVisibility, - onScroll: prevOnScroll = e => {} + onScroll: prevOnScroll = e => {}, } = this.props const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight) - // This optimization wont run, since we update the animation value directly in onScroll event + // This optimization won't run, since we update the animation value directly in onScroll event // this._maybeUpdateScrollPosition(e) if (e.nativeEvent.contentOffset.y >= p) { @@ -193,17 +200,17 @@ class ParallaxScrollView extends Component { prevOnScroll(e) } - // This optimizes the state update of current scrollY since we don't need to - // perform any updates when user has scrolled past the pivot point. - _maybeUpdateScrollPosition(e) { - const { parallaxHeaderHeight, stickyHeaderHeight } = this.props - const { scrollY } = this - const { nativeEvent: { contentOffset: { y: offsetY } } } = e - const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight) - if (offsetY <= p || scrollY._value <= p) { - scrollY.setValue(offsetY) - } - } + // // This optimizes the state update of current scrollY since we don't need to + // // perform any updates when user has scrolled past the pivot point. + // _maybeUpdateScrollPosition(e) { + // const { parallaxHeaderHeight, stickyHeaderHeight } = this.props + // const { scrollY } = this + // const { nativeEvent: { contentOffset: { y: offsetY } } } = e + // const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight) + // if (offsetY <= p || scrollY._value <= p) { + // scrollY.setValue(offsetY) + // } + // } _maybeUpdateViewDimensions(e) { const { nativeEvent: { layout: { width, height } } } = e @@ -211,7 +218,7 @@ class ParallaxScrollView extends Component { if (width !== this.state.viewWidth || height !== this.state.viewHeight) { this.setState({ viewWidth: width, - viewHeight: height + viewHeight: height, }) } } @@ -223,7 +230,7 @@ class ParallaxScrollView extends Component { parallaxHeaderHeight, stickyHeaderHeight, renderBackground, - outputScaleValue + outputScaleValue, }) { const { viewWidth, viewHeight } = this.state const { scrollY } = this @@ -240,7 +247,7 @@ class ParallaxScrollView extends Component { ? interpolate(scrollY, { inputRange: [0, p * (1 / 2), p * (3 / 4), p], outputRange: [1, 0.3, 0.1, 0], - extrapolate: 'clamp' + extrapolate: 'clamp', }) : 1, transform: [ @@ -249,18 +256,18 @@ class ParallaxScrollView extends Component { inputRange: [0, p], outputRange: [0, -(p / backgroundScrollSpeed)], extrapolateRight: 'extend', - extrapolateLeft: 'clamp' - }) + extrapolateLeft: 'clamp', + }), }, { scale: interpolate(scrollY, { inputRange: [-viewHeight, 0], - outputRange: [outputScaleValue, 1], - extrapolate: 'clamp' - }) - } - ] - } + outputRange: [outputScaleValue * 1.5, 1], + extrapolate: 'clamp', + }), + }, + ], + }, ]} > @@ -274,7 +281,7 @@ class ParallaxScrollView extends Component { fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, - renderForeground + renderForeground, }) { const { scrollY } = this const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight) @@ -289,10 +296,10 @@ class ParallaxScrollView extends Component { ? interpolate(scrollY, { inputRange: [0, p * (1 / 2), p * (3 / 4), p], outputRange: [1, 0.3, 0.1, 0], - extrapolate: 'clamp' + extrapolate: 'clamp', }) - : 1 - } + : 1, + }, ]} > @@ -310,7 +317,8 @@ class ParallaxScrollView extends Component { const { viewHeight } = this.state const containerStyles = [{ backgroundColor: contentBackgroundColor }] - if (contentContainerStyle) containerStyles.push(contentContainerStyle) + if (contentContainerStyle) + containerStyles.push(contentContainerStyle) return ( {renderStickyHeader - ? - - {renderStickyHeader()} - - - : null} + ? + {scrollingStickyHeader + ? + {renderStickyHeader()} + + : renderStickyHeader() + } + + : null + } {renderFixedHeader && renderFixedHeader()} ) @@ -416,8 +434,9 @@ ParallaxScrollView.defaultProps = { renderParallaxHeader: renderEmpty, // Deprecated (will be removed in 0.18.0) renderForeground: null, stickyHeaderHeight: 0, - contentContainerStyle: null, - outputScaleValue: 5 + contentContainerStyle: null, + scrollingStickyheader: true, + outputScaleValue: 5, } module.exports = ParallaxScrollView diff --git a/src/styles.js b/src/styles.js index 4562277..5195bd1 100644 --- a/src/styles.js +++ b/src/styles.js @@ -1,34 +1,34 @@ -const StyleSheet = require('react-native').StyleSheet; +const StyleSheet = require('react-native').StyleSheet const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: 'transparent' + backgroundColor: 'transparent', }, parallaxHeaderContainer: { backgroundColor: 'transparent', - overflow: 'hidden' + overflow: 'hidden', }, parallaxHeader: { backgroundColor: 'transparent', - overflow: 'hidden' + overflow: 'hidden', }, backgroundImage: { position: 'absolute', backgroundColor: 'transparent', overflow: 'hidden', - top: 0 + top: 0, }, stickyHeader: { backgroundColor: 'transparent', position: 'absolute', overflow: 'hidden', top: 0, - left: 0 + left: 0, }, scrollView: { - backgroundColor: 'transparent' - } -}); + backgroundColor: 'transparent', + }, +}) -module.exports = styles; +module.exports = styles diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..2f3cdec --- /dev/null +++ b/yarn.lock @@ -0,0 +1,28 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +loose-envify@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +prop-types@^15.5.10: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1"