Ripple effect v React Native

Na konci tohoto tutoriálu budeme mít přesně takovýto výsledek

V tomto prvním článku se pokusím vysvětlit, jak docílit ripple efektu nad icon tlačítkem, který známe z Material Design od Google.

To vše pomocí Animated API, které nám React Native nabízí.

Ukázka je převzata z open source knihovny react-native-material-ui, kterou vyvíjím spolu s rezervačním systémem Reservio.

Myšlenka …

Vytvoříme si tři View. Jedno jako container pro komponentu, druhé Animated pro ripple efekt a třetí bude samotná ikonka. Celé to zabalíme do TouchableWithoutFeedback komponenty, která nám poslouží pro zachytávání onPressIn a onPressOut událostí.

Proč potřebujeme onPressIn a onPressOut události? Protože se při animaci dějí dvě věci. Jednak provadíme scale animaci a pak provádíme opacity animaci. Tyhle dvě animace mohou běžet zároveň a nebo jedna po druhé. Záleží na tom, kdy uživatel stiskne tlačítko (onPressIn) a kdy uživatel pustí tlačítko (onPressOut). Tohle chování jsem nasimuloval na červené hvězdě, kterou při prvním kliknutí držím o něco déle.

Pojďme na to …

Nejdříve si vytvoříme samotné View. Poté vytvoříme IconToggle komponentu. V dalším kroce budeme animovat ripple efekt. A nakonec doladíme drobnosti, jako je barva a podobně.

Tímto jsme vytvořili View s Toolbarem, tak jak jej známe z Material Design. Protože není cílem tohoto tutoriálu ukázat, jak takový Toolbar vytvořit, tak jsem si jej vypůjčil z react-native-material-ui knihovny. Dále jsme do View vložili IconToggle komponenty, které naimplementujeme v následujícím Gistu.

Opět jsem si vypůjčil Icon komponentu z react-native-material-ui. Tímto se dostanete do následujícího stavu. A teď už jen to nejzábavnější.

Statické View společně s ikonkami

Pojďme animovat …

Na řádcích 14 a 15 jsme vytvořili Animated.Value, jednu pro scale a druhou pro opacity animaci. Ty později předáme přes style prop do Animated.View a budeme čekat na událost, kterou vyvolá kliknutí na ikonku. V té se spouští samotná animace. Ve funkci onPressedIn nejprve scale, která se animuje od 0.01 do 1 (React Native má problém se scale od nuly). A později v onPressedOut, jakmile uživatel pustí ikonku, ripple view začne pozvolna mizet (opacity animace). Opacity hodnotu nastavujeme od maxOpacity do nuly. Po skončení opacity animace musíme zpět nastavit puvodní hodnoty, tedy scale na 0.01 a opacity na maxOpacity, aby bylo vše nachystané na příští kliknutí. To děláme v callback funkci, kterou předáváme do start funkce na řádku 32. A to je vše. Tohle se stará o námi chtěný ripple efekt.

V tomto kousku kódu pouze přidáme barvu pro ikonku a ripple efekt. Za zmínku pak stojí řádky 12 a 18, kde pro Android platformu definujeme použítí nativního vlákna místo JS vlákna. V realné aplikaci totiž při stisknutí posíláme onPress event a můžeme očekávat, že aplikace dále pracuje s touto událostí. Tyhle další výpočty se s velkou pravděpodobností dějí v JS vláknu a je tedy s výkonostního hlediska žádáné, aby se animace prováděli v nativním vlákně, které neblokuje JS vlákno.

Závěrem …

Kompletní kód lze vidět v mém Gistu. Podotýkám, že tento kód není připravený pro produkci a slouží pouze jako ukázka práce s Animated API. Do produkce můžete využít react-native-material-ui knihovnu, kterou vyvíjím jako open source společně s rezervačním systémem vznikajícím u nás v reservio.com.