Skip to content

Commit 632c4d1

Browse files
authored
Merge pull request #7 from zachgibson/feature/allow-background-and-foreground-component-injection
API 1.0.0
2 parents 1091524 + c8439d4 commit 632c4d1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+4268
-1868
lines changed

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"react-native/no-color-literals": 0,
2525
"class-property/class-property-semicolon": 2,
2626
"prefer-class-properties/prefer-class-properties": 2,
27-
"react/require-default-props": 0
27+
"react/require-default-props": 0,
28+
"max-len": ["error", 80]
2829
}
2930
}

.npmignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
examples

README.md

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,87 +14,88 @@ __Features__
1414
![Vevo Demo](https://user-images.githubusercontent.com/10658888/30244668-66164c3a-9588-11e7-9cfa-c0c5dc29090c.gif)
1515
![Lightbox Demo](https://user-images.githubusercontent.com/10658888/30244669-68924b4e-9588-11e7-9426-b081953115fc.gif)
1616

17-
## Installation
17+
## Examples
18+
Check out the GIF examples above via [Expo](https://expo.io/@zachgibson/ParallaxSwiperExample). Or clone this repo and:
1819
```shell
19-
$ yarn add react-native-parallax-swiper
20+
$ cd examples/ParallaxSwiperExample
21+
$ npm install
22+
$ react-native link
23+
$ react-native run-ios
2024
```
2125

26+
## Installation
27+
```shell
28+
$ npm install react-native-parallax-swiper --save
29+
```
2230

2331
## Usage
2432
```javascript
25-
import ParallaxSwiper from 'react-native-parallax-swiper';
33+
import { ParallaxSwiper, ParallaxSwiperPage } from 'react-native-parallax-swiper';
2634
```
2735

2836
```javascript
2937
constructor() {
3038
super();
31-
39+
3240
this.myCustomAnimatedValue = new Animated.Value(0);
3341
}
3442
```
3543

3644
```javascript
3745
<ParallaxSwiper
38-
parallaxStrength={80}
39-
animatedScrollValue={this.myCustomAnimatedValue}
46+
speed={0.25}
47+
animatedValue={this.myCustomAnimatedValue}
4048
dividerWidth={8}
4149
dividerColor="black"
4250
backgroundColor="#fff"
4351
onMomentumScrollEnd={activePageIndex => console.log(activePageIndex)}
4452
>
45-
<Animated.View
46-
style={{
47-
flex: 1,
48-
alignItems: "center",
49-
justifyContent: "center",
50-
opacity: this.myCustomAnimatedValue.interpolate({
51-
inputRange: [0, deviceWidth * 0.25],
52-
outputRange: [1, 0]
53-
})
54-
}}
55-
backgroundImage={`https://source.unsplash.com/user/erondu/${deviceHeight + 1}x${deviceWidth + 1}`}
56-
>
57-
<Text>Parallaxing is rad</Text>
58-
</Animated.View>
59-
<View
60-
style={{
61-
flex: 1,
62-
alignItems: "center",
63-
justifyContent: "center"
64-
}}
65-
backgroundImage={`https://source.unsplash.com/user/erondu/${deviceHeight}x${deviceWidth}`}
66-
>
67-
<Text>Parallaxing is too rad</Text>
68-
</View>
53+
<ParallaxSwiperPage
54+
BackgroundComponent={<FireVideoComponent />}
55+
ForegroundComponent={<SickUI />}
56+
/>
57+
<ParallaxSwiperPage
58+
BackgroundComponent={<FireVideoComponent />}
59+
ForegroundComponent={<SickUI />}
60+
/>
61+
<ParallaxSwiperPage
62+
BackgroundComponent={<FireVideoComponent />}
63+
ForegroundComponent={<SickUI />}
64+
/>
6965
</ParallaxSwiper>
7066
```
7167

72-
## Props
68+
## ParallaxSwiper Props
7369
| Prop | Type | Default | Description |
7470
|---|---|---|---|
75-
| __`parallaxStrength`__ | _Number_ | `80` | This number determines how slow parallax’ing element moves. Lower number yields a subtler parallax effect, higher number increases parallax effect. |
71+
| __`speed`__ | _Number_ | `0.25` | This number determines how fast `BackgroundComponent` moves. Set to 0 for no movement at all, set to 1 and background will move as fast as the scroll. |
7672
| __`dividerWidth`__ | _Number_ | `8` | The width of the divider between each page. (horizontal only) |
7773
| __`dividerColor`__ | _String_ | `black` | Color of divider. |
78-
| __`backgroundImage`__ | _String_ | `N/A` | The image source. If used this becomes the background image that parallaxes. (remote URL only for now) |
79-
| __`backgroundImageResizeMode`__ | _String_ | `cover` | Determines how to resize the image. |
80-
| __`backgroundColor`__ | _String_ | `black` | The main view’s background color. |
74+
| __`backgroundColor`__ | _String_ | `black` | ParallaxSwiper’s background color. |
8175
| __`scrollToIndex`__ | _Function_ | 0 | Scrolls to index with a smooth animation. If used onComponentDidMount scroll is immediate with no animation. |
82-
| __`onMomentumScrollEnd`__ | _Function_ | `N/A` | Called when ScrollView stops scrolling and is passed the current page index. |
83-
| __`animatedScrollValue`__ | _Animated.Value_ | `0` | Optionally pass a new instance of Animated.Value to this prop to have access to the animated scroll value to animate your own components. |
84-
| __`children`__ | _ReactComponents_ | `N/A` | JSX to inject into the page. |
85-
| __`vertical`__ | _Boolean_ | `false` | When true, ParallaxSwiper’s children are arranged vertically in a column instead of horizontally in a row. For now only iOS supports this, but there is work to implement vertical paging on Android. |
76+
| __`onMomentumScrollEnd`__ | _Function_ | `N/A` | Fired when ScrollView stops scrolling and is passed the current page index. |
77+
| __`animatedValue`__ | _Number (Animated.Value)_ | `0` | Optionally pass a new instance of Animated.Value to access the animated value outside of ParallaxSwiper. |
78+
| __`vertical`__ | _Boolean_ | `false` | When true, ParallaxSwiper’s children are arranged vertically in a column instead of horizontally in a row. For now only iOS supports this. |
8679
| __`showsHorizontalScrollIndicator`__ | _Boolean_ | `false` | When true, shows a horizontal scroll indicator. The default value is false. |
8780
| __`showsVerticalScrollIndicator`__ | _Boolean_ | `false` | When true, shows a vertical scroll indicator. The default value is false. |
81+
| __`children`__ | _React component (ParallaxSwiperPage)_ | `N/A` | Each top-level ParallaxSwiperPage child. |
82+
83+
## ParallaxSwiperPage Props
84+
| Prop | Type | Default | Description |
85+
|---|---|---|---|
86+
| __`BackgroundComponent`__ | _React element_ | `N/A` | This component will render in the background of the page and will be animated based on scroll. |
87+
| __`ForegroundComponent`__ | _React element_ | `N/A` | This component will render in the foreground of the page. |
8888

8989
## TODO
90-
- [ ] Create Expo demos
91-
- [ ] Create examples
90+
- [x] Create Expo demos
91+
- [x] Create examples
9292
- [x] Expose current index
9393
- [x] Support scrollToIndex
9494
- [x] Fix Android
9595
- [x] Expose Animated.Value for animation outside of ParallaxSwiper
9696
- [ ] Add drag effects e.g. zoom, blur, darken
9797
- [ ] Expose rest of [ScrollView](http://facebook.github.io/react-native/releases/0.47/docs/scrollview.html#scrollview) props
98+
- [ ] Use FlatList instead of ScrollView
9899

99100
## Why another parallax component? 😒
100101
This component is inspired by an iOS pattern that no react-native-parallax-whatever previously delivered. It emulates this pattern by using the [ScrollView](http://facebook.github.io/react-native/releases/0.48/docs/scrollview.html) component which has features like velocity, paging, and platform specific easing curves; It also has optional dividers to split up each page. You can see this pattern in apps like [iOS Camera Roll](https://goo.gl/GY3bFQ), [Twitter Moments](https://goo.gl/CvzCQA), [Kylie Jenner’s app](https://goo.gl/yDB69S), [Vevo’s app](https://goo.gl/FMSSeF), and more.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["react-native"]
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
[android]
3+
target = Google Inc.:Google APIs:23
4+
5+
[maven_repositories]
6+
central = https://repo1.maven.org/maven2
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
[ignore]
2+
; We fork some components by platform
3+
.*/*[.]android.js
4+
5+
; Ignore "BUCK" generated dirs
6+
<PROJECT_ROOT>/\.buckd/
7+
8+
; Ignore unexpected extra "@providesModule"
9+
.*/node_modules/.*/node_modules/fbjs/.*
10+
11+
; Ignore duplicate module providers
12+
; For RN Apps installed via npm, "Libraries" folder is inside
13+
; "node_modules/react-native" but in the source repo it is in the root
14+
.*/Libraries/react-native/React.js
15+
16+
; Ignore polyfills
17+
.*/Libraries/polyfills/.*
18+
19+
[include]
20+
21+
[libs]
22+
node_modules/react-native/Libraries/react-native/react-native-interface.js
23+
node_modules/react-native/flow/
24+
25+
[options]
26+
emoji=true
27+
28+
module.system=haste
29+
30+
munge_underscores=true
31+
32+
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
33+
34+
suppress_type=$FlowIssue
35+
suppress_type=$FlowFixMe
36+
suppress_type=$FlowFixMeProps
37+
suppress_type=$FlowFixMeState
38+
suppress_type=$FixMe
39+
40+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
41+
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
42+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
43+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
44+
45+
unsafe.enable_getters_and_setters=true
46+
47+
[version]
48+
^0.56.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pbxproj -text
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# OSX
2+
#
3+
.DS_Store
4+
5+
# Xcode
6+
#
7+
build/
8+
*.pbxuser
9+
!default.pbxuser
10+
*.mode1v3
11+
!default.mode1v3
12+
*.mode2v3
13+
!default.mode2v3
14+
*.perspectivev3
15+
!default.perspectivev3
16+
xcuserdata
17+
*.xccheckout
18+
*.moved-aside
19+
DerivedData
20+
*.hmap
21+
*.ipa
22+
*.xcuserstate
23+
project.xcworkspace
24+
25+
# Android/IntelliJ
26+
#
27+
build/
28+
.idea
29+
.gradle
30+
local.properties
31+
*.iml
32+
33+
# node.js
34+
#
35+
node_modules/
36+
npm-debug.log
37+
yarn-error.log
38+
39+
# BUCK
40+
buck-out/
41+
\.buckd/
42+
*.keystore
43+
44+
# fastlane
45+
#
46+
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47+
# screenshots whenever they are needed.
48+
# For more information about the recommended setup visit:
49+
# https://docs.fastlane.tools/best-practices/source-control/
50+
51+
*/fastlane/report.xml
52+
*/fastlane/Preview.html
53+
*/fastlane/screenshots
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

examples/ParallaxSwiperExample/App.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import React, { Component } from 'react';
2+
import {
3+
StyleSheet,
4+
Text,
5+
View,
6+
TouchableOpacity,
7+
ScrollView,
8+
StatusBar,
9+
} from 'react-native';
10+
11+
import { SafeAreaView, StackNavigator } from 'react-navigation';
12+
import { Typography } from 'react-native-typography';
13+
14+
import Twitter from './screens/Twitter';
15+
import Vevo from './screens/Vevo';
16+
17+
const ExampleRoutes = {
18+
Twitter: {
19+
name: 'Twitter Moments',
20+
description: 'Re-creation of Twitter’s Moments feature.',
21+
screen: Twitter,
22+
},
23+
Vevo: {
24+
name: 'Vevo',
25+
description: 'Re-creation of the old Vevo app.',
26+
screen: Vevo,
27+
},
28+
};
29+
30+
class MainScreen extends Component {
31+
componentDidMount() {
32+
StatusBar.setHidden(true, 'none');
33+
}
34+
35+
render() {
36+
const { navigation } = this.props;
37+
38+
return (
39+
<ScrollView stickyHeaderIndices={[0]} style={styles.scrollView}>
40+
<View style={styles.navBar}>
41+
<Typography
42+
iOSTextStyle="title1"
43+
androidTextStyle="headline"
44+
style={{ color: '#BFBFBF' }}
45+
>
46+
ParallaxSwiper Demos
47+
</Typography>
48+
</View>
49+
{Object.keys(ExampleRoutes).map((routeName, i) =>
50+
(<TouchableOpacity
51+
key={routeName}
52+
onPress={() => {
53+
const { path, params, screen } = ExampleRoutes[routeName];
54+
const { router } = screen;
55+
const action =
56+
path && router.getActionForPathAndParams(path, params);
57+
navigation.navigate(routeName, {}, action);
58+
}}
59+
>
60+
<SafeAreaView
61+
style={[
62+
styles.itemContainer,
63+
{ borderTopWidth: i === 0 ? StyleSheet.hairlineWidth : 0 },
64+
]}
65+
forceInset={{ vertical: 'never' }}
66+
>
67+
<View style={styles.item}>
68+
<Typography
69+
iOSTextStyle="callout"
70+
androidTextStyle="body2"
71+
style={{ color: '#BFBFBF' }}
72+
>
73+
{ExampleRoutes[routeName].name}
74+
</Typography>
75+
<Typography
76+
iOSTextStyle="caption1"
77+
androidTextStyle="caption"
78+
style={{ color: '#777' }}
79+
>
80+
{ExampleRoutes[routeName].description}
81+
</Typography>
82+
</View>
83+
</SafeAreaView>
84+
</TouchableOpacity>),
85+
)}
86+
</ScrollView>
87+
);
88+
}
89+
}
90+
const AppNavigator = StackNavigator(
91+
{
92+
...ExampleRoutes,
93+
Index: {
94+
screen: MainScreen,
95+
},
96+
},
97+
{
98+
initialRouteName: 'Index',
99+
headerMode: 'none',
100+
mode: 'modal',
101+
},
102+
);
103+
104+
export default () => <AppNavigator />;
105+
106+
const styles = StyleSheet.create({
107+
scrollView: {
108+
backgroundColor: 'black',
109+
},
110+
navBar: {
111+
paddingTop: 32,
112+
paddingBottom: 16,
113+
paddingHorizontal: 16,
114+
backgroundColor: 'black',
115+
},
116+
item: {
117+
paddingHorizontal: 16,
118+
paddingVertical: 12,
119+
},
120+
itemContainer: {
121+
borderBottomWidth: StyleSheet.hairlineWidth,
122+
borderColor: '#222',
123+
backgroundColor: '#111',
124+
},
125+
});

0 commit comments

Comments
 (0)