expo-splash-screenでのアニメーションサンプル
React Native / Expo で「Linky Notes」という無料のノートアプリを
個人開発しリリースしました。
はじめての React Native を利用した開発だったこともあり、
色々と気づきがあったことをアウトプットしたく初投稿します🙇♂
背景
「Linky Notes」では初回起動時に Splash Screen が
フェードアニメーションするように実装しています。
この実装にあたって 公式のサンプルコード を参考にしつつ、
TypeScriptで書き直したうえでバンドルした画像を利用するように変更しました。
サンプルコード
アプリのコードそのままではないものの、
サンプルで動くコードを以下リポジトリに用意しました。
アニメーションさせる実装についてかんたんな補足
いくつかポイントをご紹介します。
expo-splash-screen
通常、Expo のプロジェクトではassest/splash.png
を配置するだけで
アプリの起動時にその画像を表示してくれる仕様です。
これを例えばアニメーションさせたいケースなど、
明示的に画像の表示・非表示をコントロールするために
expo-splash-screen が提供されています。
アニメーションさせる方法
冒頭でご紹介したとおり、公式のサンプルコード が用意されているので、
基本的にはこちらのコードを参考にすれば実装可能です。
「Linky Notes」の場合は以下の要件があったため、
参考にしつつ書き直して実装したという背景です。
- TypeScriptを利用
- 画像はダウンロードせずローカルのバンドルした画像を利用したい
画像については直接参照するのみなので割愛しますが、
アニメーションの流れについてはポイントを抜粋します。
スプラッシュ画像の自動非表示を止める
assest/splash.png
に画像を配置し初回起動時に画像を表示した場合、
アプリが表示できる状態になると自動で非表示になる仕様です。
expo-splash-screen
のpreventAutoHideAsync()
を利用することで、
明示的にスプラッシュ画像を非表示にしないようにすることができます。
import * as SplashScreen from 'expo-splash-screen'
// Instruct SplashScreen not to hide yet, we want to do this manually
SplashScreen.preventAutoHideAsync().catch(() => {
/* reloading the app might trigger some race conditions, ignore them */
})
アプリの準備状態の管理
useState
を利用してアプリの準備状態は管理しています。
const [isAppReady, setAppReady] = useState(false)
const [isSplashComplete, setSplashComplete] = useState(false)
-
isAppReady
はアプリの準備状態 -
isSplashComplete
はスプラッシュスクリーンのアニメーション完了判定- 再度ホーム画面に戻ってきたときにアニメーションしないようにするフラグ
画像の準備ができるとonLoadEnd
属性に渡している
onImageLoaded
関数が呼ばれます。
// Presentation
<Animated.Image
style={{
width: '100%',
height: '100%',
resizeMode: splashResizeMode,
}}
source={imagePath}
onLoadEnd={onImageLoaded}
fadeDuration={0}
/>
// Container
const onImageLoaded = useCallback(() => {
void (async () => {
try {
await SplashScreen.hideAsync()
} catch (e) {
console.log(e)
} finally {
// isAppReadyをtrueにする
setIsAppReady(true)
}
})()
}, [])
isAppReady
がtrue
になるとアニメーションが開始するという流れです。
useEffect(() => {
// isAppReadyがtrueになったらアニメーションを開始
if (isAppReady) {
// ここでアニメーションの内容を指定
Animated.timing(animation, {
toValue: 0,
duration: 1000,
useNativeDriver: true,
}).start(() => setIsSplashComplete(true))
}
}, [isAppReady, animation])
最後に
普段はWEB寄りのフロントエンジニアですが、
モバイルアプリ開発はまた違った楽しさがありました。
知識不足の点もあると思いますが、
参考になれば幸いです🙇♂
Discussion