├── package.json ├── src ├── styles.js └── index.js └── README.md /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@opengeekslab/react-native-paper-onboarding", 3 | "version": "1.0.2", 4 | "description": "You can be used at the initial screen of the application, for a visual demonstration of the functions of the app. You can also show in quick access what has been changed or added, just swipe the screen left or right", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/openGeeksLab/react-native-paper-onboarding" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "keywords": [ 14 | "react-native", 15 | "ios", 16 | "android", 17 | "paper-onboarding" 18 | ], 19 | "author": "openGeeksLab", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/openGeeksLab/react-native-paper-onboarding/issues" 23 | }, 24 | "homepage": "https://github.com/openGeeksLab/react-native-paper-onboarding/#README.md", 25 | "dependencies": { 26 | "prop-types": "^15.6.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: 'rgb(255, 255, 255)', 7 | }, 8 | indicator: { 9 | height: 8, 10 | width: 8, 11 | borderWidth: 1, 12 | borderRadius: 5, 13 | marginHorizontal: 4, 14 | }, 15 | activeIndicator: { 16 | borderColor: 'white', 17 | backgroundColor: 'white', 18 | borderRadius: 6, 19 | height: 11, 20 | width: 11, 21 | }, 22 | inactiveIndicator: { 23 | borderColor: 'white', 24 | backgroundColor: 'transparent', 25 | }, 26 | indicatorContainer: { 27 | flexDirection: 'row', 28 | position: 'absolute', 29 | bottom: 30, 30 | width: '100%', 31 | alignItems: 'center', 32 | justifyContent: 'center', 33 | backgroundColor: 'transparent', 34 | }, 35 | tabnabIndicatorContainer: { 36 | flexDirection: 'row', 37 | }, 38 | tabIndicatorRight: { 39 | flex: 1, 40 | flexDirection: 'row', 41 | justifyContent: 'flex-end', 42 | alignItems: 'center', 43 | }, 44 | tabActiveContainer: { 45 | alignItems: 'center', 46 | }, 47 | tabIndicatorLeft: { 48 | flex: 1, 49 | flexDirection: 'row', 50 | alignItems: 'center', 51 | }, 52 | nextScreenContainer: { 53 | flex: 1, 54 | position: 'absolute', 55 | height: '100%', 56 | width: '100%', 57 | }, 58 | screenAnimatedContainer: { 59 | flex: 1, 60 | }, 61 | rippleView: { 62 | position: 'absolute', 63 | width: 10, 64 | height: 10, 65 | }, 66 | }); 67 | 68 | export default styles; 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
16 |
17 | # About
18 | Our company provides custom UI design and development solutions for mobile applications and websites.
19 |
20 | Need a team to create a project?
21 |
22 | This project is developed and maintained by openGeeksLab LLC.
23 |
24 |
25 |
26 |
27 | # react-native-paper-onboarding
28 |
29 | ## Requirements
30 | - React Native 0.50+
31 | - iOS 9.0+
32 | - Android 4.2+
33 |
34 | ## Installation
35 | Just run:
36 | - npm i @opengeekslab/react-native-paper-onboarding
37 |
38 | ## Basic usage
39 | The library depends on that each screen should contain a static backgroundColor field which contains the desired background color for this screen. The screen itself should have a transparent background
40 | ```javascript
41 | import React, { Component } from 'react';
42 |
43 | import PaperOnboarding from 'react-native-paper-onboarding';
44 |
45 | import Screen1 from './screens/screen1';
46 | import Screen2 from './screens/screen2';
47 | import Screen3 from './screens/screen3';
48 |
49 | const screens = [Screen1, Screen2, Screen3];
50 |
51 | export default class App extends Component {
52 | render() {
53 | return (
54 |
138 |
139 | # Licence
140 | Expanding is released under the MIT license.
141 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | PanResponder,
5 | Dimensions,
6 | Animated,
7 | View,
8 | } from 'react-native';
9 |
10 | import styles from './styles';
11 |
12 | const { width, height } = Dimensions.get('screen');
13 | const RESPOND_THRESHHOLD = width / 3;
14 |
15 |
16 | const viewRadiusInterpolation = {
17 | inputRange: [0, 1],
18 | outputRange: [5, height / 2],
19 | };
20 |
21 | const viewRadiusInterpolationR = {
22 | inputRange: [0, 1],
23 | outputRange: [height / 2, 5],
24 | };
25 |
26 | const fadeInInterpolation = {
27 | inputRange: [0, 1],
28 | outputRange: [0.0, 1],
29 | };
30 |
31 | const fadeOutInterpolation = {
32 | inputRange: [0, 1],
33 | outputRange: [1.0, 0.0],
34 | };
35 |
36 | const viewScaleInterpolation = {
37 | inputRange: [0, 1],
38 | outputRange: [0, (height * 2) / 5],
39 | };
40 |
41 | const viewScaleInterpolationR = {
42 | inputRange: [0, 1],
43 | outputRange: [(height * 2) / 5, 0],
44 | };
45 |
46 | const tabpanelInterpolation = {
47 | inputRange: [0, 1],
48 | outputRange: [0, -12],
49 | };
50 |
51 | const tabpanelInterpolationR = {
52 | inputRange: [0, 1],
53 | outputRange: [0, 12],
54 | };
55 |
56 | class PaperOnboardingContainer extends Component {
57 | static propTypes = {
58 | screens: PropTypes.array,
59 | }
60 |
61 | constructor(props) {
62 | super(props);
63 | const routes = this.props.screens.map(item => React.createElement(item));
64 | this.nextBackground = 0;
65 | this.state = {
66 | routes,
67 | currentScreen: 0,
68 | animationFinish: true,
69 | nextPoint: { x: 0, y: 0 },
70 | isSwipeDirectionLeft: true,
71 | rootBackground: this.props.screens[0].backgroundColor,
72 | backgroundAnimation: new Animated.Value(0),
73 | panResponder: PanResponder.create({
74 | onStartShouldSetPanResponder: () => true,
75 | onStartShouldSetPanResponderCapture: () => true,
76 | onMoveShouldSetResponderCapture: () => true,
77 | onMoveShouldSetPanResponderCapture: () => true,
78 | onPanResponderRelease: (e, gestureState) => {
79 | const { x0, y0, dx, dy } = gestureState; // eslint-disable-line object-curly-newline
80 |
81 | const nextPoint = {
82 | x: x0 + dx,
83 | y: y0 + dy,
84 | };
85 |
86 | if (Math.abs(dx) >= RESPOND_THRESHHOLD) {
87 | if (dx > 0) {
88 | this.onSwipe('right', nextPoint);
89 | } else {
90 | this.onSwipe('left', nextPoint);
91 | }
92 | }
93 | return true;
94 | },
95 | }),
96 | };
97 | }
98 |
99 | onSwipe(swipeDirection, nextPoint) {
100 | const { currentScreen } = this.state;
101 | const nextIndex = this.getNextScreenIndex(swipeDirection);
102 |
103 | const isSwipeDirectionLeft = swipeDirection === 'left';
104 |
105 | this.nextBackground = isSwipeDirectionLeft
106 | ? this.props.screens[nextIndex].backgroundColor
107 | : this.props.screens[currentScreen].backgroundColor;
108 |
109 | this.startBackgroundAnimation(
110 | currentScreen,
111 | nextIndex,
112 | nextPoint,
113 | isSwipeDirectionLeft,
114 | );
115 | }
116 |
117 | getNextScreenIndex(direction) {
118 | const { currentScreen, routes } = this.state;
119 | let directionModifier = 0;
120 | if (direction === 'left') {
121 | directionModifier = 1;
122 | } else if (direction === 'right') {
123 | directionModifier = -1;
124 | }
125 |
126 | let nextIndex = currentScreen + directionModifier;
127 | if (nextIndex < 0) {
128 | nextIndex = routes.length - 1;
129 | } else if (nextIndex >= routes.length) {
130 | nextIndex = 0;
131 | }
132 | return nextIndex;
133 | }
134 |
135 | callAnimations = (currentScreen, nextIndex) => {
136 | const { backgroundAnimation } = this.state;
137 | const { screens } = this.props;
138 | Animated.timing(
139 | backgroundAnimation,
140 | { toValue: 1, duration: 900 },
141 | ).start(() => {
142 | backgroundAnimation.setValue(0);
143 | this.nextBackground = screens[currentScreen].backgroundColor;
144 |
145 | this.setState({
146 | nextIndex: null,
147 | animationFinish: true,
148 | currentScreen: nextIndex,
149 | rootBackground: screens[nextIndex].backgroundColor,
150 | nextPoint: { x: 0, y: 0 },
151 | });
152 | });
153 | }
154 |
155 | startBackgroundAnimation = (currentScreen, nextIndex, nextPoint, isSwipeDirectionLeft) => {
156 | this.setState(
157 | {
158 | nextIndex,
159 | nextPoint,
160 | isSwipeDirectionLeft,
161 | animationFinish: false,
162 | rootBackground: isSwipeDirectionLeft
163 | ? this.props.screens[currentScreen].backgroundColor
164 | : this.props.screens[nextIndex].backgroundColor,
165 | },
166 | () => this.callAnimations(currentScreen, nextIndex),
167 | );
168 | }
169 |
170 | renderRippleBackground(screen, backgroundColor, isSwipeDirectionLeft = true) {
171 | const { backgroundAnimation, nextPoint, animationFinish } = this.state;
172 | const radius = isSwipeDirectionLeft ? viewRadiusInterpolationR : viewRadiusInterpolation;
173 | const scale = isSwipeDirectionLeft ? viewScaleInterpolation : viewScaleInterpolationR;
174 | if (!animationFinish) {
175 | return (
176 |