電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 今回は、 Expoの公式チュートリアル をやっていきたいと思います。 プロジェクトの作成 Download assets Install dependencies アプリの実行 コードの編集 テキストの文字色の変更 イメージの表示 ImageViewerコンポーネント Buttonコンポーネント PhotoButtonコンポーネント 画像の選択 まとめ 仲間募集 プロジェクトの作成 StickerSmash プロジェクトを作成しましょう。 npx create-expo-app StickerSmash && cd StickerSmash Download assets https://docs.expo.dev/static/images/tutorial/sticker-smash-assets.zip をダウンロードしてから解凍し、StickerSmash/assetsに格納します。既存のファイルは置き換えてください。 Install dependencies Webでも実行できるようにするために、必要なモジュールをインストールします。 npx expo install react-dom react-native-web @expo/webpack-config アプリの実行 プロジェクトの ディレクト リで、 npx expo start を実行します。 wを押すと、Webアプリを試すことができます。 次のように表示されました。 コードの編集 プロジェクトの ディレクト リで、 code . を実行して、 VS Code を立ち上げます。 背景を #25292e に変更しましょう。 const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#25292e", alignItems: "center", justifyContent: "center", }, }); 次のように表示されました。 テキストのデフォルトの文字色は黒なので、背景が黒っぽくなったことで、文字が見え辛くなってしまいました。 テキストの文字色の変更 Textタグのstyle属性で、文字の色を白に指定しましょう。 <Text style={{ color: "#fff" }}> Open up App.js to start working on your app! </Text> 次のように表示されました。 イメージの表示 イメージを表示しましょう。 Image コンポーネント をインポートします。 import { StyleSheet, View, Image } from 'react-native'; 次は、イメージパスの設定です。 const PlaceholderImage = require('./assets/images/background-image.png'); Imageタグを使う前に、 スタイルシート の設定をしましょう。 const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#25292e", alignItems: "center", }, imageContainer: { flex: 1, paddingTop: 58, }, image: { width: 320, height: 440, borderRadius: 18, }, }); 準備ができたので、Image コンポーネント を使ってみましょう。 <View style={styles.imageContainer}> <Image source={PlaceholderImage} style={styles.image} /> </View> 下記のように表示されました。 ImageViewer コンポーネント 先ほど作ったイメージ表示機能を コンポーネント 化しましょう。 StickSmash ディレクト リの中にcomponents ディレクト リを作成します。 .../StickerSmash$ mkdir components VS Code で ImageViewer.js を作成します。 code components/ImageViewer.js 下記のコードを ImageViewer.js に書き込みます。 import { StyleSheet, Image } from 'react-native'; export default function ImageViewer({ placeholderImageSource }) { return ( <Image source={placeholderImageSource} style={styles.image} /> ); } const styles = StyleSheet.create({ image: { width: 320, height: 440, borderRadius: 18, }, }); App.js から ImageViewer.js を呼び出します。 import ImageViewer from './components/ImageViewer'; const PlaceholderImage = require('./assets/images/background-image.png'); export default function App() { return ( <View style={styles.container}> <View style={styles.imageContainer}> <ImageViewer placeholderImageSource={PlaceholderImage} /> </View> <StatusBar style="auto" /> </View> ); } 見た目はもちろん以前と一緒です。 Button コンポーネント これからボタンを2つ作りますが、その前に、Button コンポーネント を作ってそれを利用することにしましょう。 VS Code で Button.js を作成します。 code components/Button.js 下記のコードを Button.js に書き込みます。 import { StyleSheet, View, Pressable, Text } from 'react-native'; export default function Button({ label }) { return ( <View style={styles.buttonContainer}> <Pressable style={styles.button} onPress={() => alert('You pressed a button.')}> <Text style={styles.buttonLabel}>{label}</Text> </Pressable> </View> ); } const styles = StyleSheet.create({ buttonContainer: { width: 320, height: 68, marginHorizontal: 20, alignItems: 'center', justifyContent: 'center', padding: 3, }, button: { borderRadius: 10, width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', flexDirection: 'row', }, buttonLabel: { color: '#fff', fontSize: 16, }, }); App.js から Button.js を呼び出します。 import Button from './components/Button'; <View style={styles.footerContainer}> <Button label="Choose a photo" /> <Button label="Use this photo" /> </View> const styles = StyleSheet.create({ // Styles that are unchanged from previous step are hidden for brevity. footerContainer: { flex: 1 / 3, alignItems: 'center', }, }); 下記のように表示されました。 PhotoButton コンポーネント 写真アイコンが表示されるボタンを作りましょう。 @expo/vector-icon をインストールします。 npx expo install @expo/vector-icons VS Code で PhotoButton.js を作成します。 code components/PhotoButton.js 下記のコードを PhotoButton.js に書き込みます。 import { StyleSheet, View, Pressable, Text } from "react-native"; import FontAwesome from "@expo/vector-icons/FontAwesome"; export default function PhotoButton({ label }) { return ( <View style={styles.buttonContainer}> <Pressable style={styles.button} onPress={() => alert("You pressed a button.")} > <FontAwesome name="picture-o" size={18} color="#25292e" style={styles.buttonIcon} /> <Text style={[styles.buttonLabel, {}]}>{label}</Text> </Pressable> </View> ); } const styles = StyleSheet.create({ buttonContainer: { width: 320, height: 68, marginHorizontal: 20, alignItems: "center", justifyContent: "center", padding: 3, borderWidth: 4, borderColor: "#ffd33d", borderRadius: 18, }, button: { borderRadius: 10, width: "100%", height: "100%", alignItems: "center", justifyContent: "center", flexDirection: "row", backgroundColor: "#fff", }, buttonIcon: { paddingRight: 8, }, buttonLabel: { color: "#25292e", fontSize: 16, }, }); 下記のように表示されました。 画像の選択 画像を選択する機能を実装しましょう。 expo-image-picker をインストールします。 npx expo install expo-image-picker App.js で pickImageAsync ファンクションを実装しましょう。選択した画像は、 result.assets[0].uri に入っています。 import * as ImagePicker from 'expo-image-picker'; const pickImageAsync = async () => { const result = await ImagePicker.launchImageLibraryAsync({ allowsEditing: true, quality: 1, }); if (!result.canceled) { alert(result.assets[0].uri); } else { alert('You did not select any image.'); } }; PhotoButton でボタンを押したときの動作が定義できるように、 onPress 属性を追加しましょう。 export default function PhotoButton({ label, onPress }) { return ( <View style={styles.buttonContainer}> <Pressable style={styles.button} onPress={onPress} > <FontAwesome name="picture-o" size={18} color="#25292e" style={styles.buttonIcon} /> <Text style={styles.buttonLabel>{label}</Text> </Pressable> </View> ); } App.js で PhotoButton が押されたときに、 pickImageAsync ファンクションを呼び出します。 <PhotoButton label="Choose a photo" onPress={pickImageAsync} /> ImageViewer で選択した画像を表示できるように、 selectedImage 属性を追加します。 export default function ImageViewer( { placeholderImageSource, selectedImage }) { const imageSource = selectedImage ? { uri: selectedImage } : placeholderImageSource; return <Image source={imageSource} style={styles.image} />; } App.js で、写真が選択されたら、 ImageViewer に表示します。 import { useState } from "react"; const PlaceholderImage = require("./assets/images/background-image.png"); export default function App() { const [selectedImage, setSelectedImage] = useState(null); const pickImageAsync = async () => { const result = await ImagePicker.launchImageLibraryAsync({ allowsEditing: true, quality: 1, }); if (!result.canceled) { setSelectedImage(result.assets[0].uri); } else { alert("You did not select any image."); } }; return ( <View style={styles.container}> <View style={styles.imageContainer}> <ImageViewer placeholderImageSource={PlaceholderImage} selectedImage={selectedImage} /> </View> <View style={styles.footerContainer}> <PhotoButton label="Choose a photo" onPress={pickImageAsync} /> <Button label="Use this photo" /> </View> <StatusBar style="auto" /> </View> ); } 下記のように表示されました。 切りが良いので、前編はここまでとします。 まとめ Expoの公式チュートリアル は、難易度もちょうどいい感じで、実践的な力が身につくなと感じました。ただ、 JavaScript じゃなくTypeScriptにしてほしかったところです。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア 執筆: @higa ( Shodo で執筆されました )