Untuk membangun aplikasi yang lebih interaktif, salah satunya adalah dengan memberikan animasi pada aplikasi kita, saya rasa kita semua sudah tahu apa itu animasi, tapi pada konteks programming, animasi adalah proses dimana sebuah component bertransformasi atau berubah style secara halus.
Visual Feedback misalnya saat user menekan sebuah button, kita bisa memberikan feedback dengan memberikan animasi pada button tersebut setelah diklik, agar user yakin bahwa buttonnya sudah berhasil ditekan, jadi user tidak menekan button tersebut berulang-ulang.
Current Status pada saat user pertama kali membuka aplikasi, terkadang ada data yang harus kita fetch dari API, saat proses fetch data tersebut sedang berlangsung, kita bisa menambahkan animasi loading untuk memberi tahu user bahwa saat ini aplikasi kita sedang loading. dan tentunya dengan adanya animasi akan lebih enak dilihat daripada hanya tampilan blank putih.
Connect Transitions dengan adanya animasi, antar kondisi atau state aplikasi kita menjadi jelas, misalnya mulai dari saat user di halaman login, user menekan tombol login lalu muncul indikator loading dan user berhasil login. perubahannya jelas.
User Attention animasi juga bisa meningkatkan UX aplikasi kita, user menjadi lebih tertarik dan nyaman saat menggunakan aplikasi kita. tapi jika terlalu banyak animasi juga tidak bagus, user nanti malah bingung dan tidak fokus. jadi gunakan animasi seperlunya saja :)
Animated merupakan library untuk membuat animasi yang sudah disediakan oleh React Native, library ini dirancang untuk membuat animasi yang fluid, powerfull, dan mudah untuk digunakan.
Sama seperti pada animation CSS3, library ini menggunakan konsep keyframe, keyframe itu seperti step-step berjalannya animasi kita nanti, keyframe-keyframe tersebut nantinya akan kita convert menjadi value yang kita pakai untuk styling menggunakan method interpolate.
Animated.timing() digunakan untuk membuat animasi yang bisa kita tentukan kurva speednya sendiri.
Animated.decay() value animasi dimulai dari inisialisasi velocity dan perlahan akan melambat menjadi 0.
Animated.spring() ketika keyframe animasinya sudah di akhir akan muncul efek bounce.
Animated API juga menyediakan method-method yang bisa kita gunakan untuk mengkombinasikan animasi-animasi kita.
Animated.parallel() digunakan untuk menjalankan animasi secara bersamaan.
Animated.sequence() animasi-animasi kita akan dijalankan secara berurutan, jika animasi nya di stop, animasi selanjutnya tidak akan dijalankan.
Animated.stagger() animasi-animasi akan dijalankan dalam waktu bersamaan dan berurutan, tapi kita bisa mengatur jeda waktu pada setiap animasi yang akan dijalankan.
Method ini biasanya digunakan untuk membuat indikator loading, atau animasi lain yang dijalankan secara berulang-ulang tanpa henti (infinite loop), menurutku method ini sangat powerfull, bahkan kita bisa membuat sendiri animasi spring dan decay menggunakan method ini 😍
1import React from "react";2import { View, StyleSheet, Animated, Easing } from "react-native";
untuk menggunakannya kita import terlebih dahulu modul Animated dan Easing.
Animated merupakan library dari React Native untuk membuat animasi, sedangkan Easing adalah modul yang menyediakan banyak sekali variasi pergerakan animasi, seperti : linear, ease, bezier, bounce, dll.
untuk melihat variasi Easing secara visual, kalian bisa mengunjungi easings.net
1class App extends React.Component {2 constructor() {3 super();4 this.spinValue = new Animated.Value(0);5 }6}78export default App;
kita inisialisasi dulu state spinValue dengan nilai awal 0, menggunakan method new Animated.Value(), jika kita ingin menggunakan 2 value kita bisa menggunakan method new Animated.ValueXY() biasanya digunakan untuk pan gestures
1componentDidMount() {2 this.spin();3}
pada saat component kita dimount, kita panggil method this.spin yang akan kita buat nantinya, method ini akan menjalankan animasi spin.
1spin() {2 this.spinValue.setValue(0);3 Animated.timing(this.spinValue, {4 toValue: 1,5 duration: 1000,6 easing: Easing.linear,7 }).start(() => this.spin());8}
ketika method spin() dipanggil, kita set state spinValue menjadi 0
mengapa kita set spinValue menjadi 0 ? padahal didalam constructor kita sudah menginisialisasi valuenya 0, karena pada saat method spin dipanggil kedua kalinya, spinValue nilainya berubah menjadi 1, jadi harus kita set lagi valuenya menjadi 0 agar animasinya berjalan dengan baik.
setelah itu kita panggil method Animated.timing yang menganimasikan state spinValue dari 0 menjadi 1 dengan durasi satu detik. dan menggunakan tipe easing linear yang kita dapat dari modul Easing.
Animated.timing menerima 2 argumen, yang pertama adalah value dan yang kedua adalah konfigurasi yang bertipe data object, konfigurasi ini berisi :
toValue
easing
delay
isInteraction
useNativeDriver
Kemudian kita panggil method start pada method Animated.timing untuk menjalankan animasinya. didalam method start, kita passing sebuah callback yang memanggil method spin, callback ini akan dipanggil setelah method Animated.timing selesai dijalankan, jadi nanti method spin ini akan dijalankan berulang ulang tanpa henti (infinite loop).
1render() {2 const spin = this.spinValue.interpolate({3 inputRange: [0, 1],4 outputRange: ['0deg', '360deg'],5 });6 return (7 <View style={styles.container}>8 <Animated.View style={{transform: [{rotate: spin}]}}>9 <View style={styles.box} />10 </Animated.View>11 </View>12 );13}
pada saat component kita dirender, kita buat variabel bernama spin, didalamnya kita panggil method interpolate dari state spinValue, method ini menerima object yang berisi inputRange dan outputRange, method interpolate akan mengconvert inputRange menjadi outputRange, keyframe 0 akan bernilai 0deg dan keyframe 1 akan bernilai 360deg , kita juga bisa menambahkan keyframe yang lain, 0.5 misalnya.
1// contoh2const spin = this.spinValue.interpolate({3 inputRange: [0, 0.5, 1],4 outputRange: ["0deg", "300deg", "360deg"],5});
selanjutnya kita bungkus View yang akan kita animasikan dengan component Animated.View, pada component Animated.View kita menambahkan style transform rotate yang value nya dari variabel spin.
kenapa kita menggunakan Animated.View bukan View biasa ? karena kalau kita menggunakan View biasa, kita tidak bisa menggunakan variabel spin sebagai value dari rotate, karena value nya harus string.
Terakhir, kita buat styling pada component kita
1const styles = StyleSheet.create({2 container: {3 flex: 1,4 justifyContent: "center",5 alignItems: "center",6 },7 box: {8 width: 200,9 height: 200,10 backgroundColor: "#26a267",11 },12});
Seperti yang kita ketahui, method Animated.spring() akan memberikan efek bounce ketika keyframe animasinya berada di akhir. biasanya digunakan untuk animasi pop up atau notifikasi. untuk mencobanya, kita akan menggunakan kode yang sebelumnya, karena tidak banyak yang kita ubah.
Pertama ganti variabel spinValue menjadi springValue dan ubah valuenya menjadi 1
1constructor() {2 super();3 this.springValue = new Animated.Value(1);4}
kemudian pada componentDidMount() ganti this.spin() menjadi this.spring()
1componentDidMount() {2 this.spring();3}
setelah itu hapus method spin() dan buat method baru yang bernama spring()
1spring() {2 this.springValue.setValue(1);3 Animated.spring(this.springValue, {4 toValue: 1.25,5 friction: 0.1,6 tension: 100,7 }).start();8}
Kita set state springValue menjadi 1
Sama seperti sebelumnya, Animated.spring juga menerima 2 argumen, pertama adalah value dan yang kedua adalah konfigurasi yang bertipe data object. konfigurasi yang wajib diisi adalah toValue. tapi friction dan tension bisa kita gunakan jika kita ingin kontrol lebih pada animasi spring kita, semakin besar tension, efek bounce yang dihasilkan semakin besar. sedangkan, semakin besar friction, efek bouncenya akan semakin kecil. untuk mengetahui konfigurasi apa saja yang bisa dilakukan, kita bisa melihatnya disini
Setelah itu kita panggil method start() untuk menjalankan animasinya.
1render() {2 return (3 <View style={styles.container}>4 <Animated.View style={{transform: [{scale: this.springValue}]}}>5 <View style={styles.box} />6 </Animated.View>7 </View>8 );9}
selanjutnya hapus variabel spin pada method render(), karena sudah tidak diperlukan lagi. dan ganti rotate: this.spinValue menjadi scale: this.springValue.
Animation.decay ini digunakan untuk kasus-kasus tertentu, membuat gesture misalnya, method ini membutuhkan inisialisasi velocity (kecepatan awal), berdasarkan nilai velocity tersebut dan nilai deceleration dia akan menghitung nilai akhir dan durasi animasinya. misalnya, kita menggunakan transform translate, jika velocity nya tinggi maka perpindahan element nya menjadi jauh dan cepat, tapi jika velocity nya rendah maka element nya akan berpindah beberapa pixel saja. sedangkan deceleration itu perlambatannya, sama seperti fungsi rem pada kendaraan. sebagai contoh, kita akan menggunakan kode kita yang sebelumnya lagi.
Pertama ganti variabel springValue menjadi decayValue dan ubah valuenya menjadi 0
1constructor() {2 super();3 this.decayValue = new Animated.Value(0);4}
kemudian pada componentDidMount() ganti this.spring() menjadi this.decay()
1componentDidMount() {2 this.decay();3}
setelah itu hapus method spring() dan buat method baru yang bernama decay()
1decay() {2 this.decayValue.setValue(0);3 Animated.decay(this.decayValue, {4 velocity: 2,5 deceleration: 0.996, // default 0.9976 }).start();7}
Sama seperti contoh sebelumnya, Animated.decay juga menerima 2 argumen, pertama adalah value dan yang kedua adalah konfigurasi yang bertipe data object. value animasi dimulai dari inisialisasi velocity dan perlahan akan melambat lalu berhenti sesuai dengan konfigurasi deceleration. untuk mengetahui konfigurasi apa saja yang bisa dilakukan, kita bisa melihatnya disini
Method ini akan menjalankan animasi animasi kita secara bersamaan dalam waktu yang sama. cara penggunaannya tinggal kita tampung method animasi kita ke dalam sebuah variabel kemudian variabel-variabel tersebut kita masukkan ke dalam array, lalu array yang berisi animasi2 tersebut kita pakai sebagai argumen dari method Animation.parallel() dan jangan lupa untuk menjalankan animasinya dengan method start()
Method ini akan menjalankan animasi animasi kita secara berurutan, dan menunggu animasi yang sedang berjalan selesai baru lanjut ke animasi berikutnya, jika animasi yang sedang berjalan dihentikan maka animasi selanjutnya tidak akan dijalankan. cara penggunaannya sama seperti sebelumnya, kita masukkan animasi-animasi kita kedalam array, lalu kita pakai sebagai argumennya.
Animation.stagger ini bisa dikatakan sebagai kombinasi antara method Animated.parallel dengan method Animated.sequence, dia akan dijalankan dalam waktu bersamaan dan berurutan, tapi kita bisa mengatur delay waktu pada setiap animasi yang akan dijalankan, Animation.stagger membutuhkan 2 argumen, yang pertama adalah delay ( milidetik ) dan yang kedua adalah array yang berisi animasi-animasi kita.
itu tadi beberapa method pada Animated API yang akan sering kita gunakan, jika kamu ingin membuat animasi yang lebih kompleks atau ingin mempelajari lebih detail, kalian bisa mengunjungi dokumentasi React Animated API disini :)
Oke mungkin itu saja yang bisa saya bagikan kali ini, kalau kamu merasa artikel ini bermanfaat silakan Like & Share artikel ini ke teman-teman kamu atau jika kamu punya pertanyaan, tulis aja di kolom komentar, Thank you! 😁 🙏
Always open to new ideas. 🕊️
Articles that you might want to read.
Tutorial membuat infinity scroll dan skeleton loading pada React JS
Tutorial membuat background Image pada teks dengan CSS3...
Tutorial Drag & Drop React JS menggunakan react-beautiful-dnd