Skip to content

Commit 22f18ac

Browse files
authored
Replace underlayWidth with snapPoints (#4)
* convert underLayWidth to snapPoints * fix snapTo logic * fix onClose * add fling approximation
1 parent f71efa5 commit 22f18ac

File tree

2 files changed

+203
-98
lines changed

2 files changed

+203
-98
lines changed

README.md

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ _NOTE:_ Naming is hard. When you swipe _right_, you reveal the item on the _left
2121
type RenderUnderlay<T> = (params: {
2222
item: T;
2323
percentOpen: Animated.Node<number>;
24-
open: () => Promise<void>;
24+
open: (snapToIndex?: number) => Promise<void>;
2525
close: () => Promise<void>;
2626
}) => React.ReactNode;
2727

2828
type RenderOverlay<T> = (params: {
2929
item: T;
30-
openLeft: () => Promise<void>;
31-
openRight: () => Promise<void>;
30+
openLeft: (snapToIndex?: number) => Promise<void>;
31+
openRight: (snapToIndex?: number) => Promise<void>;
3232
close: () => Promise<void>;
3333
}) => React.ReactNode;
3434

@@ -39,23 +39,23 @@ enum OpenDirection {
3939
}
4040
```
4141

42-
| Name | Type | Description |
43-
| :-------------------- | :-------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
44-
| `renderUnderlayLeft` | `RenderUnderlay` | Component to be rendered underneath row on left swipe. |
45-
| `renderUnderlayRight` | `RenderUnderlay` | Component to be rendered underneath row on left swipe. |
46-
| `underlayWidthLeft` | `number` | Width of left-swiped underlay. |
47-
| `underlayWidthRight` | `number` | Width of right-swiped underlay. |
48-
| `renderOverlay` | `RenderOverlay` | Component to be rendered on top. Use if you need access to programmatic open/close methods. May altenatively pass children to SwipeableItem. |
49-
| `onChange` | `(params: { open: OpenDirection }) => void` | Called when row is opened or closed. |
50-
| `swipeEnabled` | `boolean` | Enable/disable swipe. Defaults to `true`. |
51-
| `activationThreshold` | `number` | Distance finger must travel before swipe engages. Defaults to 20. |
42+
| Name | Type | Description |
43+
| :-------------------- | :---------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
44+
| `renderUnderlayLeft` | `RenderUnderlay` | Component to be rendered underneath row on left swipe. |
45+
| `renderUnderlayRight` | `RenderUnderlay` | Component to be rendered underneath row on left swipe. |
46+
| `snapPointsLeft` | `number[]` | Pixel values left-swipe snaps to (eg. [100, 300]) |
47+
| `snapPointsRight` | `number[]` | Pixel values right-swipe snaps to (eg. [100, 300]) |
48+
| `renderOverlay` | `RenderOverlay` | Component to be rendered on top. Use if you need access to programmatic open/close methods. May altenatively pass children to SwipeableItem. |
49+
| `onChange` | `(params: { open: OpenDirection, snapTo: number }) => void` | Called when row is opened or closed. |
50+
| `swipeEnabled` | `boolean` | Enable/disable swipe. Defaults to `true`. |
51+
| `activationThreshold` | `number` | Distance finger must travel before swipe engages. Defaults to 20. |
5252

5353
### Instance Methods
5454

55-
| Name | Type | Description |
56-
| :------ | :------------------------------------- | :--------------------------------------------------------------- |
57-
| `open` | `(OpenDirection.LEFT \| OpenDirection.RIGHT) => Promise<void>` | Programmatically open left or right. Promise resolves once open. |
58-
| `close` | `() => Promise<void>` | Close all. Promise resolves once closed. |
55+
| Name | Type | Description |
56+
| :------ | :--------------------------------------------------------------------------------- | :--------------------------------------------------------------- |
57+
| `open` | `(OpenDirection.LEFT \| OpenDirection.RIGHT, snapIndex?: number) => Promise<void>` | Programmatically open left or right. Promise resolves once open. |
58+
| `close` | `() => Promise<void>` | Close all. Promise resolves once closed. |
5959

6060
```js
6161
// Programmatic open example
@@ -83,14 +83,30 @@ import {
8383
StyleSheet,
8484
FlatList,
8585
LayoutAnimation,
86-
TouchableOpacity
86+
Platform,
87+
UIManager,
88+
TouchableOpacity,
89+
Dimensions
8790
} from "react-native";
91+
92+
const { width } = Dimensions.get("window");
93+
94+
import { TouchableOpacity as RNGHTouchableOpacity } from "react-native-gesture-handler";
8895
import Animated from "react-native-reanimated";
89-
import SwipeableItem from "react-native-swipeable-item";
96+
import SwipeableItem from "./SwipeableItem";
97+
// import SwipeableItem from 'react-native-swipeable-item';
9098
import DraggableFlatList from "react-native-draggable-flatlist";
9199
const { multiply, sub } = Animated;
92100

93-
const NUM_ITEMS = 10;
101+
const isAndroid = Platform.OS === "android";
102+
103+
if (isAndroid && UIManager.setLayoutAnimationEnabledExperimental) {
104+
UIManager.setLayoutAnimationEnabledExperimental(true);
105+
}
106+
107+
const PlatformTouchable = isAndroid ? TouchableOpacity : TouchableOpacity;
108+
109+
const NUM_ITEMS = 3;
94110
function getColor(i) {
95111
const multiplier = 255 / (NUM_ITEMS - 1);
96112
const colorVal = i * multiplier;
@@ -100,7 +116,9 @@ function getColor(i) {
100116
const initialData = [...Array(NUM_ITEMS)].fill(0).map((d, index) => ({
101117
text: `Row ${index}`,
102118
key: `key-${index}`, // Note: It's bad practice to use index as your key. Don't do it in production!
103-
backgroundColor: getColor(index)
119+
backgroundColor: getColor(index),
120+
hasLeft: index % 3 === 0 || index % 3 === 1,
121+
hasRight: index % 3 === 0 || index % 3 === 2
104122
}));
105123

106124
class App extends React.Component {
@@ -121,9 +139,9 @@ class App extends React.Component {
121139
<Animated.View
122140
style={[styles.row, styles.underlayLeft, { opacity: percentOpen }]} // Fade in on open
123141
>
124-
<TouchableOpacity onPressOut={() => this.deleteItem(item)}>
142+
<PlatformTouchable onPressOut={() => this.deleteItem(item.item)}>
125143
<Text style={styles.text}>{`[x]`}</Text>
126-
</TouchableOpacity>
144+
</PlatformTouchable>
127145
</Animated.View>
128146
);
129147

@@ -137,17 +155,44 @@ class App extends React.Component {
137155
}
138156
]}
139157
>
140-
<TouchableOpacity onPressOut={close}>
158+
<PlatformTouchable onPressOut={close}>
141159
<Text style={styles.text}>CLOSE</Text>
142-
</TouchableOpacity>
160+
</PlatformTouchable>
143161
</Animated.View>
144162
);
145163

164+
renderOverlay = ({ item, openLeft, openRight, openDirection, close }) => {
165+
const { text, backgroundColor, hasLeft, hasRight } = item.item;
166+
return (
167+
<View style={[styles.row, { backgroundColor }]}>
168+
<View style={[styles.flex, { alignItems: "flex-start" }]}>
169+
{hasRight && (
170+
<PlatformTouchable
171+
onPressOut={!!openDirection ? close : () => openRight(1)}
172+
>
173+
<Text style={styles.text}>{`<`}</Text>
174+
</PlatformTouchable>
175+
)}
176+
</View>
177+
<PlatformTouchable style={styles.flex} onLongPress={item.drag}>
178+
<Text style={styles.text}>{text}</Text>
179+
</PlatformTouchable>
180+
<View style={[styles.flex, { alignItems: "flex-end" }]}>
181+
{hasLeft && (
182+
<PlatformTouchable onPressOut={!!openDirection ? close : openLeft}>
183+
<Text style={styles.text}>{`>`}</Text>
184+
</PlatformTouchable>
185+
)}
186+
</View>
187+
</View>
188+
);
189+
};
190+
146191
renderItem = ({ item, index, drag }) => {
147192
return (
148193
<SwipeableItem
149194
key={item.key}
150-
item={item}
195+
item={{ item, drag }}
151196
ref={ref => {
152197
if (ref && !this.itemRefs.get(item.key)) {
153198
this.itemRefs.set(item.key, ref);
@@ -161,26 +206,21 @@ class App extends React.Component {
161206
});
162207
}
163208
}}
164-
overSwipe={1000}
209+
overSwipe={50}
165210
renderUnderlayLeft={this.renderUnderlayLeft}
166-
underlayWidthLeft={100}
211+
snapPointsLeft={item.hasLeft ? [100] : undefined}
167212
renderUnderlayRight={this.renderUnderlayRight}
168-
underlayWidthRight={200}
169-
>
170-
<View style={[styles.row, { backgroundColor: item.backgroundColor }]}>
171-
<TouchableOpacity onLongPress={drag}>
172-
<Text style={styles.text}>{item.text}</Text>
173-
</TouchableOpacity>
174-
</View>
175-
</SwipeableItem>
213+
snapPointsRight={item.hasRight ? [100, width] : undefined}
214+
renderOverlay={this.renderOverlay}
215+
/>
176216
);
177217
};
178218

179219
render() {
180220
return (
181221
<View style={styles.container}>
182222
<DraggableFlatList
183-
activationDistance={15} // <-- add if your DraggableFlatList list is not scrolling
223+
activationDistance={15}
184224
keyExtractor={item => item.key}
185225
data={this.state.data}
186226
renderItem={this.renderItem}
@@ -197,11 +237,14 @@ const styles = StyleSheet.create({
197237
container: {
198238
flex: 1
199239
},
240+
flex: {
241+
flex: 1
242+
},
200243
row: {
201244
flexDirection: "row",
202245
flex: 1,
203246
alignItems: "center",
204-
justifyContent: "center",
247+
justifyContent: "space-around",
205248
padding: 15
206249
},
207250
text: {

0 commit comments

Comments
 (0)