Reputation: 23
I'm new to React Native and as well to Animations in React Native. What I'm trying to do is to fill the checkbox in it's pressed but the way I did made all the checkboxes fill when I press the Touchable Opacity.
the 'color' value is defined by this
const color = useRef(new Animated.Value(0)).current;
I don't know if this is the best way. I searched through the documentation and saw something like this.
const {
clean,
tasks,
getTasksList,
edited,
toogleEdited,
deleteList,
} = useContext(listContext);
const { taskEdited } = useContext(taskContext);
const [listName, setListName] = useState("");
const screenHeight = Math.round(Dimensions.get("window").height);
const colors = useRef(
Array.from({ length: tasks.length }).fill(new Animated.Value(0))
);
async function getListName() {
setListName(await AsyncStorage.getItem("listName"));
}
async function asyncGetTasks() {
await getTasksList();
}
useEffect(() => {
getListName();
asyncGetTasks();
}, [edited, taskEdited]);
return (
<View style={styles.container}>
<StatusBar hidden />
<View style={styles.buttonsContainer}>
<TouchableOpacity
onPress={() => {
clean();
navigation.goBack();
}}
>
<MaterialIcons name="arrow-back" size={32} />
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
deleteList();
clean();
navigation.goBack();
}}
>
<MaterialIcons name="delete" size={32} color="#bc0000" />
</TouchableOpacity>
</View>
<View style={styles.titleContent}>
<Text style={styles.titleText}>{listName}</Text>
</View>
<ScrollView style={{ height: screenHeight }}>
{tasks.length > 0 ? (
tasks.map((item, index) => (
<TouchableOpacity key={index} style={styles.task}>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
style={{ alignSelf: "center", marginRight: 8 }}
onPress={() => {
console.log(colors.current[index]);
Animated.timing(colors.current[index], {
toValue: 1,
duration: 1000,
}).start();
toogleEdited();
}}
>
<Animated.View
style={{
borderColor: "#000",
borderWidth: 3,
borderRadius: 100,
}}
>
<Animated.View
style={{
backgroundColor: "#000",
height: 22,
width: 22,
borderRadius: 100,
opacity: colors.current[index],
}}
nativeID={item._id}
></Animated.View>
</Animated.View>
</TouchableOpacity>
<View>
<Text style={styles.taskText}>{item.title}</Text>
</View>
</View>
<Animated.View
style={{
position: "absolute",
alignItems: "center",
alignContent: "center",
opacity: 0.5,
alignSelf: "center",
}}
>
<Text
style={{
color: "#000",
opacity: 0,
fontSize: 32,
}}
>
Done!!
</Text>
</Animated.View>
</TouchableOpacity>
))
) : (
<View style={styles.emptyContent}>
<Text style={styles.emptyText}>This list don't have tasks yet</Text>
</View>
)}
</ScrollView>
<TouchableOpacity
style={{
position: "absolute",
top: screenHeight - 120,
right: 28,
flexDirection: "row",
width: 50,
alignSelf: "flex-end",
}}
onPress={() => navigation.navigate("NewTask")}
>
<Image source={PlusImage} />
</TouchableOpacity>
</View>
);
}
If you don't understand please feel free to ask, my code can be difficult to read but I'm working on that!
edit: I tried some advises that I got here but still does to all and showed more of the code to be more compreensive
Upvotes: 1
Views: 593
Reputation: 2877
You store all elements as only one ref
, you should make it more dynamic like that
const colors = useRef(Array.from({length: tasks.length} , _ => new Animated.Value(0))).current
use .from({ length }, _ => ...)
for creating an array with unique object for each slot in the array (and not same object pointed by all slots)
Now you able to change only one element in onPress
onPress={() => {
console.log(colors[index]);
Animated.timing(colors[index], {
toValue: 1,
duration: 1000,
}).start();
}}
Another notes,
Don't use TouchableOpacity
where you don't need onPress
functionality, it's blocking it children clickability
For achieving animated behavior in Animated.View
, you should chain the animation value with view style
prop
<Animated.View
style={{ ...yourStyle... ,
opacity: colors[index],
}}
>
will create fading animation, while opacity
will be 0 / 1 accords animation value
Upvotes: 2