React Native – podstawowe animacje
Odpowiednio zastosowane mikroanimacje tworzone w React Native mogą pozytywnie wpływać na interakcje użytkownika z naszą aplikacją. Nie tylko uatrakcyjniają jej wygląd i sprawiają, że używanie jej jest bardziej ciekawe, ale również zapewniają użytkownika o tym, że jego działania faktycznie mają wpływ na aplikacje (np. loadery).
Dla początkujących programistów React Native temat animacji może wydać się skomplikowany. Mnogość opcji w postaci takich bibliotek jak Reanimated, Animatable czy Lottie React Native, może przytłaczać, a kod animacji pisanych z podstawową biblioteką Animated może wyglądać dość nieprzyjaźnie.
Nic bardziej mylnego. Postaram się pokazać, że z użyciem biblioteki Animated można szybko tworzyć proste animacje znacznie poprawiające wygląd aplikacji.
Artykuł jest skierowany do osób, które mają podstawową wiedzę na temat tego w jaki sposób tworzyć komponenty w RN.
Checkbox - animowanie wielkości
Zacznijmy od najprostszego możliwego przykładu.
Stwórzmy w animację sprowadzającą się do zmiany wielkości wewnętrznego kwadratu w reakcji na tapnięcie ekranu przez użytkownika.

Implementacja
Zabierzmy się za implementację.
1. Najpierw stwórzmy komponent bez animacji.
type Props = {
value: boolean;
onPress: (value: boolean) =>; void;
};
const Checkbox: React.FC<Props> = ({ onPress, value }) => {
return (
<TouchableOpacity
style={styles.container}
onPress={() => {
onPress(!value);
}}>
{value && <View style={[styles.insideBox]} />}
</TouchableOpacity>
);
};
export default Checkbox;
Do komponentu przekazujemy dwa propsy:
- value, przechowujący informacje o tym czy checkbox jest zaznaczony, czy odznaczony,
- oraz funkcję onPress umożliwiającą zmianę wartości value podczas naciśnięcia na checkbox.
Komponent składa się z TouchableOpacity oraz View reprezentującego prostokąt w środku checkboxa, który renderujemy warunkowo tylko gdy wartość checkboxa wynosi true.
2. Teraz zajmijmy się nadaniem odpowiednich stylów.
const styles = StyleSheet.create({
container: {
height: 120,
width: 120,
borderColor: theme.colors.black,
backgroundColor: theme.colors.background,
borderWidth: 0.5,
borderRadius: 10,
alignItems: "center",
justifyContent: "center",
},
insideBox: {
backgroundColor: theme.colors.black,
height: 85,
width: 85,
borderRadius: 10,
},
});
Najważniejsze jest aby nadać TouchableOpacity większą szerokość i wysokość niż wewnętrznemu View.
Za ułożenie View centralnie na środku TouchableOpacity odpowiadają:
alignItems:"center"
oraz
justifyContent:"center"
Nie zapomnijmy o nadaniu wartości border w TouchableOpacity oraz koloru tła dla View.
Na tym etapie komponent powinien wyglądać mniej więcej tak:

Animacja
Nuda… prawda? Pora na dodanie animacji!
1. Na początku zaimportujmy dostarczaną przez React Native bibliotekę Animated.
import { Animated } from "react-native";
Żeby zanimować wielkość naszego wewnętrznego kwadratu należy zdefiniować nową animowalną wartość, od której uzależnimy jego wysokość i szerokość. Zamieńmy również komponent View na animowalny komponent Animated.View
const size = new Animated.Value(0);
<Animated.View
style={[
styles.insideBox,
{
height: size,
width: size,
},
]}
/>;
2. Teraz skonfigurujmy animację.
Najpierw wybierzmy jeden z trzech dostępnych typów animacji:
- Animated.spring()
- Animated.decay()
- Animated.timing()
Ja wybrałem Animated.timing(), ale zachęcam do sprawdzenia jak działają inne typy. Wszystkie informacje dostępne są w dokumentacji.
Animated.timing() przyjmuje dwa argumenty:
- jednym jest wartość, która ma być animowana (w naszym przypadku size),
- drugim obiekt z wartościami konfigurującymi animację.
W obiekcie konfiguracyjnym zdefiniujmy 3 wartości:
- toValue odpowiadającą za to do jakiej wielkości ma zmniejszyć się nasze animowane View,
- duration odpowiadającą za czas trwania animacji w milisekundach oraz
- useNativeDriver (opcja odpowiadająca za poprawienie performance, która nie wspiera jednak animacji wartości height i width stąd ustawiamy ją na false).
Poniższy kod pokazuje dwie skonfigurowane animacje:
- jedna zmienia wartość size do 85 (odpowiada za animacje przy zaznaczaniu checkboxa),
- druga zmienia wartość size do 0 (odpowiada za animacje przy odznaczaniu checkboxa).
Animated.timing(size, {
toValue: 85,
duration: 350,
useNativeDriver: false,
});
Animated.timing(size, {
toValue: 0,
duration: 350,
useNativeDriver: false,
});
Teraz w hooku useEffect w zależności od wartości value wykonajmy .start(), co spowoduje rozpoczęcie odpowiedniej animacji.
useEffect(() => {
if (value) {
Animated.timing(size, {
toValue: 85,
duration: 350,
useNativeDriver: false,
}).start();
} else {
Animated.timing(size, {
toValue: 0,
duration: 350,
useNativeDriver: false,
}).start();
}
}, [value]);
3. Gotowa animacja powinna wyglądać tak:

Zachęcam do zabawy z dostępnymi opcjami i konfiguracją animacji. Ja np. stworzyłem CheckBox z logo Dogtronic.

Animowana paginacja - animowanie zależne od scrollX
Animacje możemy również uzależnić od parametrów wejściowych.
W tym przykładzie pokażę w jaki sposób animować wielkość oraz kolor komponentu w zależności od tego w jakim stopniu została przescrollowana flat lista z obrazkami.

Implementacja
Zacznijmy od zaimplementowania flat listy wyświetlającej obrazki wraz ze wskaźnikiem pokazującym który slajd jest aktualnie wyświetlany.
1. Instalacja biblioteki swiper-flat-list.
Najpierw zainstalujmy bibliotekę swiper-flat-list zgodnie z instrukcjami.
import SwiperFlatList from "react-native-swiper-flatlist";
Utwórzmy teraz komponent flat-list. Otrzymuje on poprzez propsy tablicę obrazów. Szerokość obrazów uzależniona jest od szerokości ekranu poprzez zmienną windowWidth. Posiada on stan activeImage, który przechowuje informację o obecnie wyświetlanym obrazku.
2. Teraz zaimportujmy komponent swiper-flat-list.
interface Props {
images: any[];
}
const windowWidth = Dimensions.get("window").width;
const PaginatedFlatlist: React.FC = ({ images }) => {
const [activeImage, setActiveImage] = useState(0);
return (
<View>
<SwiperFlatList onChangeIndex={({ index }) => setActiveImage(index)}>
{images.map((image, index) => (
<Image
style={[styles.image, { width: windowWidth - 30 }]}
key={index}
source={image}
resizeMode="cover"
/>
))}
</SwiperFlatList>
</View>
);
};
export default PaginatedFlatlist;
Następnie dodajmy do komponentu paginacje. W tym celu użyjmy funkcji map na tablicy obrazów i wyświetlajmy małą czarną kropkę, lub jeśli indeks obrazu jest równy indeksowi obecnie wyświetlanego obrazu – większą niebieską kropkę.
3. Na tym etapie komponent powinien zachowywać się w następujący sposób:

import React, { useState } from "react";
import { Dimensions, Image, StyleSheet, View } from "react-native";
import SwiperFlatList from "react-native-swiper-flatlist";
interface Props {
images: any[];
}
const windowWidth = Dimensions.get("window").width;
const PaginatedFlatlist: React.FC = ({ images }) => {
const [activeImage, setActiveImage] = useState(0);
return (
<View>
<SwiperFlatList onChangeIndex={({ index }) => setActiveImage(index)}>
{images.map((image, index) => (
<Image
style={[styles.image, { width: windowWidth - 30 }]}
key={index}
source={image}
resizeMode="cover"
/>
))}
</SwiperFlatList>
<View style={styles.paginationContainer}>
{images.map((_, index) => {
return (
<View
style={[
styles.dot,
activeImage === index && styles.activeDot
]}
key={index}
/>
);
})}
</View>
</View>
);
};
export default PaginatedFlatlist;
const styles = StyleSheet.create({
image: {
justifyContent: "center",
},
paginationContainer: {
marginTop: 10,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
dot: {
height: 10,
width: 10,
margin: 7,
borderRadius: 8,
backgroundColor: "black",
},
activeDot: {
height: 14,
width: 14,
backgroundColor: "#1a51b0",
},
});
Animacja
W celu utworzenia animacji paginacji musimy w pierwszej kolejności uzyskać dostęp do wartości o jaką obecnie przescrollowany jest oponent flat list.
1. W tym celu należy zdefiniować zmienną scrollX.
const scrollX = useRef(new Animated.Value(0)).current;
Następnie w funkcji onScroll flat listy wykorzystamy Animated.event w celu zmapowania obecnego stopnia przescrollowania flaltlisty na zdefiniowaną wcześniej zmienną scrollX
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: scrollX } } }],
{ useNativeDriver: false }
)}
2. Animację utworzymy korzystając z interpolacji.
Animajcę utworzymy korzystając z interpolacji. Polega to na tym, że tworzymy nową zmienną, której wartość zależna jest od obecnej wartości innej zmiennej typu Animated.Value.
W naszym przypadku utworzymy dwie zmienne:
- dotColor odpowiadającą za zmianę koloru kropek,
- oraz dotSize odpowiadającą za ich wielkość.
Będą one zależne od obecnej wartości scrollX.
Input range jest tablicą wartości scrollX przy jakich dotColor lub dotSize mają osiągać odpowiadające wartości z tablicy output range.
Wartości (index – 1) width, (index) width i (index + 1) * width odpowiadają wartościom scrollX dla jakich powinna wyświetlać się duża niebieska kropka, kropka po niej następuje, oraz kropka je poprzedzająca.
const inputRange = [
(index - 1) * width,
index * width,
(index + 1) * width,
];
const dotSize = scrollX.interpolate({
inputRange,
outputRange: [10, 14, 10],
extrapolate: "clamp",
});
const dotColor = scrollX.interpolate({
inputRange,
outputRange: ["#000000", "#1a51b0", "#000000"],
extrapolate: 'clamp'
});
Ustawienie wartości extrapolate na clamp sprawia, że biblioteka animated nie będzie próbowała obliczyć wartości output range, jeśli wartość scrollX wyjdzie poza zakres zdefiniowany w input range. Dzięki temu wielkość kropek paginacji nie będzie mniejsza od 10.
3. Ostatnim krokiem jest nadanie odpowiednich stylów kropkom paginacji.
<Animated.View
style={[
styles.dot,
{ width: dotSize, height: dotSize, backgroundColor: dotColor },
]}
key={index}
/>
4. Ostatecznie animacja powinna wyglądać w następujący sposób:

Search
Kategorie
Ostanie komentarze
Praca w Dogtronic
Newsletter
About
Creeping they’re she’d. Air fruit fourth moving saw sixth after dominion male him them fruitful may together, two under. Night i he replenish fourth.
WP Categories
- AI 12
- Ciekawostki 11
- Dogtronic 6
- Elektronika 5
- Javascript 4
- Komputery 4
- Kursy 0
- Arduino 3
- MacOS 1
- Podstawy robotyki 2
- Porady 38
- React Native 9
- SEO 7
- Software House 7
- Web 3.0 3
- Weekly News 5