I'm currently using Swipeable to create a list of items, each of which the user can swipe to delete. It's working fine but if I swipe a row and open one and then swipe another, the previously-opened row is still swiped open but I'd like it to be closed.
I've searched for solutions and made a little progress myself using refs but I've not been able to get it working perfectly. I've also come across quite a few people asking for the same thing and it seems like pretty standard behaviour. It'd be great if you could add some documentation with examples covering this.
Thank you.
any update? 馃槶
Need help on this too! I'm working on closing Swipeable by index instead of last swiped item.
Need help on this too! I'm working on closing Swipeable by index instead of last swiped item.
Yeah, I played around with a solution like that but nothing felt that good so, unfortunately, I removed the whole swiping gesture from my app.
I tried using ref as well and it seems to be working fine except that the close animation is delayed a little.
Hi, can someone help me. T tried the example project but when i tried to close the swipeable view but its not working. Am I missing or doingsomething.. Any help is really appreciated. Thank you so much.
this is the sample project link : https://github.com/kmagiera/react-native-gesture-handler/blob/master/Example/swipeable/AppleStyleSwipeableRow.js
Any chance we can get an update on this? It seems like a few people are wondering the same thing. Thanks!
I would like to introduce this function i my apps
I tried using
refas well and it seems to be working fine except that the close animation is delayed a little.
can you show us your workaround ?
I tried using
refas well and it seems to be working fine except that the close animation is delayed a little.can you show us your workaround ?
@AmanSharma2609 The idea is using ref and close(). Hope it helps
let row: Array<any> = [];
let prevOpenedRow;
renderItem ({ item, index }) {
return (
<Swipeable
ref={ref => row[index] = ref}
friction={2}
leftThreshold={80}
rightThreshold={40}
renderRightActions={renderRightActions}
containerStyle={style.swipeRowStyle}
onSwipeableOpen={closeRow(index)}
...
>
...
</Swipeable>);
}
closeRow(index) {
if (prevOpenedRow && prevOpenedRow !== row[index]) {
prevOpenedRow.close();
}
prevOpenedRow = row[index];
}
i use array of ref to fixed this issue, i think this issue cause by single ref, when we iterate over array the ref became the last ref of item in list so i did give all the list of item a ref based on index or item.id and called the ref based on index or id
first
constructor(props) {
super(props);
this.state = {
};
this.refsArray = []; // add this
}
then in swipeable collect the ref by passing index or your custom id
<Swipeable
ref={ref => {
this.refsArray[index] = ref; //or this.refsArray[item.id]
}}
friction={2}
leftThreshold={30}
rightThreshold={40}
renderRightActions={(progress) => this.renderRightActions(progress, item)}
>
then to close one item do this in your method
this.refsArray[index].close(); // or this.refsArray[item.id].close(); if you are using custom id
I tried using
refas well and it seems to be working fine except that the close animation is delayed a little.can you show us your workaround ?
@AmanSharma2609 The idea is using
refandclose(). Hope it helpslet row: Array<any> = []; let prevOpenedRow; renderItem ({ item, index }) { return ( <Swipeable ref={ref => row[index] = ref} friction={2} leftThreshold={80} rightThreshold={40} renderRightActions={renderRightActions} containerStyle={style.swipeRowStyle} onSwipeableOpen={closeRow(index)} ... > ... </Swipeable>); } closeRow(index) { if (prevOpenedRow && prevOpenedRow !== row[index]) { prevOpenedRow.close(); } prevOpenedRow = row[index]; }
@anniewey It worked thank you!!
I tried using
refas well and it seems to be working fine except that the close animation is delayed a little.
This solution works for me. I'm using react-native-gesture-handler v1.4.1 and we have the method _onSwipeableWillOpen()_. Try to use this instead _onSwipeableOpen()_.
List.js
let swipedCardRef = null;
const onOpen = ref => {
if (swipedCardRef) swipedCardRef.current.close();
swipedCardRef = ref;
};
const onClose = ref => {
if (ref == swipedCardRef) {
swipedCardRef = null;
}
};
const renderItem = ({ item, index }) => {
return (
<Item
item={item}
index={item}
removeItem={removeItem(item)}
onOpen={onOpen}
onClose={onClose}
/>
);
};
<Flatlist data={[...]} renderItem={renderItem} ... />
Item.js
const onSwipeOpen = () => {
if (!isOpened) {
isOpened = true;
onOpen(rowRef);
}
};
const onSwipeClose = () => {
if (isOpened) {
isOpened = false;
onClose(rowRef);
}
};
return (
<Swipeable
ref={rowRef}
renderLeftActions={renderLeftActions}
onSwipeableOpen={onSwipeOpen}
onSwipeableClose={onSwipeClose}
>
<TouchableOpacity
onPressIn={onSwipeOpen}
>
...
</TouchableOpacity>
</Swipeable>
);
It can help you!
I wrapped my list in a SwipeProvider. It uses Context to maintain the state of which item is open. When an item opens, it updates the context with an id. All the other swipe-ables use a hook to see if the currently open id matches their id. If it doesn't, they close themselves.
@calendee i鈥檓 trying to do the same thing. What prop do you use to force close the non matching rows?
@Lsleiman Sorry for the slow response.
Here's a sample: https://gist.github.com/calendee/ba37861b237b57ee49b7949766c9a0da
This seems to be working for me. Sharing just in case
let rowRefs = new Map();
const renderItem = ({item}) => (
<Swipeable
key={item.key}
ref={ref => {
if (ref && !rowRefs.get(item.key)) {
rowRefs.set(item.key, ref);
}
}}
onSwipeableWillOpen={()=>{
[...rowRefs.entries()].forEach(([key, ref]) => {
if (key !== item.key && ref) ref.close();
});
}}
>
</Swipeable>
);
rowRef
I'm getting rowRef is undefined
@ShravanMeena I used rowRefs in my example
@Lsleiman Sorry for the slow response.
Here's a sample: https://gist.github.com/calendee/ba37861b237b57ee49b7949766c9a0da
Thank you @calendee . Your solution worked for me. I had three tabs and also had to close all swipeables when switching tabs. Using react-navigation as the navigation solution. Here is a gist in case someone needs it https://gist.github.com/barunprasad/a738d944fa9abf4e6993f719b13827ad
@Lsleiman this solves my issue! Thanks alot
Here what I did:
const EMPTY_KEY = '';
const row: Array<any> = [];
const [key, setKey] = React.useState<string | any>(EMPTY_KEY);
const handleWillOpen = (index : any) => () => (key !== EMPTY_KEY) && (key !== index) && row[key].close();
const handleOpen = (index : any) => () => setKey(index);
return <Swipeable
ref={ref => row[index] = ref}
{....renders}
onSwipeableRightWillOpen={handleWillOpen(index)}
onSwipeableLeftWillOpen={handleWillOpen(index)}
onSwipeableOpen={handleOpen(index)}>
<View
{....components}
</View>
</Swipeable>
not using useCallback, or creating context whatever, just save the key, and make sure that before open some different key close the prior one.
Most helpful comment
@AmanSharma2609 The idea is using
refandclose(). Hope it helps