├── .gitignore
├── README.md
├── SwipeableElement.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Swipeable Element for React Native
2 | Experimental element that can be swiped left or right to perform different actions. This is still a major work in progress.
3 |
4 | 
5 |
6 | ### Usage
7 | ```
8 | var React = require('react-native');
9 | var {
10 | View,
11 | } = React;
12 | var SwipeableElement = require('react-native-swipeable-element');
13 |
14 | var MyComponent = React.createClass({
15 | render: function() {
16 | return (
17 |
18 | {'Some Text'}}
20 | swipeRightTitle={'Delete'}
21 | swipeRightTextColor={'#FFFFFF'}
22 | swipeRightBackgroundColor={'#000000'}
23 | swipeLeftTitle={'Archive'}
24 | swipeLeftTextColor={'#FFFFFF'}
25 | swipeLeftBackgroundColor={'#FF0000'}
26 | onSwipeRight={() => {
27 | // Handle swipe
28 | }}
29 | onSwipeLeft={() => {
30 | // Swipe left
31 | }} />
32 |
33 | );
34 | }
35 | });
36 |
37 | ```
38 |
--------------------------------------------------------------------------------
/SwipeableElement.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var React = require('react-native');
3 | var {
4 | StyleSheet,
5 | View,
6 | Text,
7 | PanResponder,
8 | LayoutAnimation,
9 | } = React;
10 | var Dimensions = require('Dimensions');
11 |
12 | var SCREEN_WIDTH = Dimensions.get('window').width;
13 | var SCREEN_HEIGHT = Dimensions.get('window').height;
14 |
15 | var SWIPE_RELEASE_POINT = 70;
16 |
17 | var styles = StyleSheet.create({
18 | swipeableElementWrapper: {
19 | width: SCREEN_WIDTH,
20 | flexDirection:'row',
21 | justifyContent:'center',
22 | },
23 | swipeableMain: {
24 | width: SCREEN_WIDTH,
25 | padding:10,
26 | backgroundColor: '#F0F0F0',
27 | },
28 | swipeableLeft: {
29 | overflow: 'hidden',
30 | width: 0,
31 | backgroundColor: '#FF0000',
32 | alignItems: 'flex-start',
33 | justifyContent:'center',
34 | },
35 | swipeableRight: {
36 | overflow: 'hidden',
37 | width: 0,
38 | alignItems: 'flex-end',
39 | backgroundColor: '#0000FF',
40 | },
41 | leftText: {
42 | color:'#FFFFFF',
43 | padding:10,
44 | alignSelf:'center',
45 | },
46 | rightText: {
47 | color:'#FFFFFF',
48 | padding:10,
49 | }
50 | });
51 |
52 | var SwipeableElement = React.createClass({
53 |
54 | _panResponder: {},
55 |
56 | _handleStartShouldSetPanResponder: function() {
57 | return true;
58 | },
59 |
60 | _handleMoveShouldSetPanResponder: function() {
61 | return true;
62 | },
63 |
64 | _handlePanResponderGrant: function() {},
65 |
66 | _handlePanResponderMove: function(e, gestureState) {
67 | if (!this.refs.mainElement) {
68 | return;
69 | }
70 |
71 | var dx;
72 | var direction = gestureState.dx > 0 ? 'right' : 'left';
73 | if (gestureState.dx < -150) {
74 | dx = -150;
75 | } else if (gestureState.dx > 150) {
76 | dx = 150;
77 | } else {
78 | dx = gestureState.dx;
79 | }
80 |
81 | var absdx = dx > 0 ? dx : -dx;
82 | var opacity = (absdx / SWIPE_RELEASE_POINT) * 1;
83 | var fontSize = 6 + ((opacity > 1 ? 1 : opacity) * 8);
84 | var paddingTop = 15 - ((opacity > 1 ? 1 : opacity) * 5);
85 | var text;
86 | var element;
87 |
88 | var props = { width: absdx*2, opacity, };
89 |
90 | this.refs.mainElement.setNativeProps({ left: dx });
91 | if (dx > 0) {
92 | element = this.refs.leftElement;
93 | props.left = absdx;
94 | text = this.refs.leftText;
95 | } else {
96 | element = this.refs.rightElement;
97 | props.right = absdx;
98 | text = this.refs.rightText;
99 | }
100 | text.setNativeProps({ fontSize, paddingTop });
101 | element.setNativeProps(props);
102 |
103 | this.setState({ dx });
104 | },
105 |
106 | _handlePanResponderEnd: function() {
107 | if (this.state.dx > SWIPE_RELEASE_POINT) {
108 | if (this.props.onSwipeRight) {
109 | this.props.onSwipeRight.call();
110 | }
111 | } else if (this.state.dx < -SWIPE_RELEASE_POINT) {
112 | if (this.props.onSwipeLeft) {
113 | this.props.onSwipeLeft.call();
114 | }
115 | }
116 | var animations = require('../../TaskList/animations');
117 | LayoutAnimation.configureNext(animations.easeInEaseOut);
118 | this.setState({dx:0,});
119 | this.refs.mainElement && this.refs.mainElement.setNativeProps({ left: 0 });
120 | this.refs.leftElement && this.refs.leftElement.setNativeProps({ width: 0, left: 0, });
121 | this.refs.rightElement && this.refs.rightElement.setNativeProps({ width: 0, right: 0,});
122 | // Reset the left/right values after the animation finishes
123 | // This feels hacky and I hope there's a better way to do this
124 | setTimeout(() => {
125 | this.refs.leftElement && this.refs.leftElement.setNativeProps({ left: null });
126 | this.refs.rightElement && this.refs.rightElement.setNativeProps({ right: null });
127 | }, 300);
128 | },
129 |
130 | componentWillMount: function() {
131 | this._panResponder = PanResponder.create({
132 | onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
133 | onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
134 | onPanResponderGrant: this._handlePanResponderGrant,
135 | onPanResponderMove: this._handlePanResponderMove,
136 | onPanResponderRelease: this._handlePanResponderEnd,
137 | onPanResponderTerminate: this._handlePanResponderEnd,
138 | });
139 | },
140 |
141 | getInitialState: function() {
142 | return { dx: 0, };
143 | },
144 |
145 | render: function() {
146 | var pullOrRelease = (this.state.dx > SWIPE_RELEASE_POINT || this.state.dx < -SWIPE_RELEASE_POINT) ?
147 | 'Release' :
148 | 'Pull';
149 |
150 | var rightTextStyle = this.props.swipeLeftTextColor ?
151 | [styles.rightText, {color: this.props.swipeLeftTextColor,}] :
152 | styles.rightText;
153 |
154 | var leftTextStyle = this.props.swipeRightTextColor ?
155 | [styles.leftText, {color: this.props.swipeRightTextColor,}] :
156 | styles.leftText;
157 |
158 | var rightElementStyle = this.props.swipeLeftBackgroundColor ?
159 | [styles.swipeableLeft, {backgroundColor: this.props.swipeLeftBackgroundColor}] :
160 | styles.swipeableLeft;
161 |
162 | var leftElementStyle = this.props.swipeRightBackgroundColor ?
163 | [styles.swipeableRight, {backgroundColor: this.props.swipeRightBackgroundColor}] :
164 | styles.swipeableRight;
165 |
166 | return (
167 |
168 |
169 |
170 |
171 |
172 | {pullOrRelease} to {this.props.swipeRightTitle}
173 |
174 |
175 |
176 |
177 | {this.props.component}
178 |
179 |
180 |
181 | {pullOrRelease} to {this.props.swipeLeftTitle}
182 |
183 |
184 |
185 | );
186 | }
187 | });
188 |
189 | module.exports = SwipeableElement;
190 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-swipeable-element",
3 | "version": "0.1.0",
4 | "description": "",
5 | "main": "SwipeableElement.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Josh Levine",
10 | "license": "MIT",
11 | "dependencies": {
12 | "react-native": "^0.3.4"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------