正如您从 gif 中看到的,我必须确保当您在一行上从右向左滑动时,该行上的图标具有缩放类型的动画。
喜欢:
当您从小处打开图标时,它会变得越来越大。 (从右向左移动)
当您从大图标关闭时,它会变得越来越小。 (从左向右移动,然后关闭)
链接:https://snack.expo.io/sAXMmE2dZ
代码:
import React, { useState, useEffect } from 'react';
import {
Text,
View,
StyleSheet,
FlatList,
LayoutAnimation,
TouchableOpacity,
Platform,
UIManager,
} from 'react-native';
import Animated from 'react-native-reanimated';
import SwipeableItem, {
UnderlayParams,
OpenDirection,
} from 'react-native-swipeable-item';
import DraggableFlatList, {
RenderItemParams,
} from 'react-native-draggable-flatlist';
const { multiply, sub } = Animated;
import { MaterialIcons } from '@expo/vector-icons';
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const OVERSWIPE_DIST = 20;
const NUM_ITEMS = 20;
type Item = {
key: string,
text: string,
taken: boolean,
height: number,
};
const initialData: Item[] = [...Array(NUM_ITEMS)].fill(0).map((d, key) => {
return {
text: `Item ${key}`,
key,
taken: false,
height: 50,
};
});
export default function App() {
const [state, setState] = useState(initialData);
const [key, setKey] = useState(1);
let itemRefs = new Map();
/*useEffect(() => {
let id;
if (key < state.length)
id = setInterval(() => {
const item = state.filter((d) => d.key === key)[0];
takenItem(item);
setKey((prev) => prev + 2);
}, 3000);
else clearInterval(id);
return () => clearInterval(id);
}, [key]);*/
const takenItem = (item: Item) => {
item.taken = !item.taken;
if (item.taken) {
const els = state.filter((el) => el.key !== item.key);
setState([...els, item]);
} else {
const noTaken = state.filter((el) => !el.taken);
const prev = noTaken.filter((el) => el.key < item.key);
const next = noTaken.filter((el) => el.key > item.key);
const taken = state
.filter((el) => el.key !== item.key)
.filter((el) => el.taken);
setState([...prev, item, ...next, ...taken]);
console.log('el', item);
console.log('prev', prev);
console.log('next', next);
console.log('taken', taken);
console.log('u', [...prev, item, ...next, ...taken]);
}
/*setState((prev) =>
prev.map((el) => (el.key === item.key ? { ...el, taken: !el.taken } : el))
);*/
[...itemRefs.entries()].forEach(([key, ref]) => {
if (key === item.key && ref) ref.close();
});
};
const deleteItem = (item: Item) => {
const updatedData = state.filter((d) => d !== item);
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
setState(updatedData);
};
const renderUnderlayRight = ({ item, percentOpen }: UnderlayParams<Item>) => (
<Animated.View
style={[
styles.underlayRight,
{
opacity: percentOpen,
transform: [{ translateX: multiply(sub(1, percentOpen), -100) }],
},
]}>
<TouchableOpacity onPressOut={() => takenItem(item)}>
<MaterialIcons
name={item.taken ? 'check-box' : 'check-box-outline-blank'}
size={24}
color="#fff"
/>
</TouchableOpacity>
</Animated.View>
);
const renderUnderlayLeft = ({ item, percentOpen }: UnderlayParams<Item>) => {
console.log(percentOpen, multiply(sub(1, percentOpen), -100));
return (
<Animated.View
style={[
styles.underlayLeft,
{
opacity: percentOpen,
},
]}>
<TouchableOpacity onPressOut={() => deleteItem(item)}>
<MaterialIcons
name="delete"
size={24}
color="#fff"
style={{
scaleX: 0.5,
scaleY: 0.5,
}}
/>
</TouchableOpacity>
</Animated.View>
);
};
const renderItem = ({ item, index, drag }: RenderItemParams<Item>) => {
return (
<SwipeableItem
key={item.key}
item={item}
ref={(ref) => {
if (ref && !itemRefs.get(item.key)) {
itemRefs.set(item.key, ref);
}
}}
onChange={({ open }) => {
if (open) {
[...itemRefs.entries()].forEach(([key, ref]) => {
if (key !== item.key && ref) ref.close();
});
}
}}
overSwipe={100}
renderUnderlayRight={renderUnderlayRight}
renderUnderlayLeft={renderUnderlayLeft}
snapPointsRight={[50]}
snapPointsLeft={[50]}>
<View
style={[
styles.row,
{
backgroundColor: item.taken ? '#4caf50' : '#2979ff',
height: item.height,
},
]}>
<TouchableOpacity onPressIn={drag}>
<MaterialIcons name="drag-handle" size={24} color="#fff" />
</TouchableOpacity>
<Text style={styles.text}>{item.text}</Text>
</View>
</SwipeableItem>
);
};
return (
<View style={styles.container}>
<DraggableFlatList
scrollEnabled={true}
keyExtractor={(item) => item.key}
data={state}
renderItem={renderItem}
onDragEnd={({ data }) => setState(data)}
activationDistance={20}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: 35,
backgroundColor: '#ecf0f1',
},
row: {
flexDirection: 'row',
flex: 1,
alignItems: 'center',
},
text: {
fontWeight: 'bold',
color: 'white',
fontSize: 15,
},
underlayRight: {
flex: 1,
backgroundColor: '#0d47a1',
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row',
paddingLeft: 5,
},
underlayLeft: {
flex: 1,
backgroundColor: '#0d47a1',
justifyContent: 'flex-end',
alignItems: 'center',
flexDirection: 'row',
paddingRight: 5,
},
});