画像ピッカーを使用する
ページを編集
このチュートリアルでは、Expo Image Picker の使い方を学びます。
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
React Native は、<View>、<Text>、<Pressable> などの組み込みコンポーネントを標準的な構成要素として提供しています。ここで作成するのは、デバイスのメディアギャラリーから画像を選択する機能です。これはコアコンポーネントだけでは実現できないため、この機能をアプリに追加するためにライブラリが必要になります。
Expo SDK のライブラリである expo-image-picker を使用します。
expo-image-pickerは、端末のライブラリから画像や動画を選択するためのシステム UI へのアクセスを提供します。

expo-image-picker を使ってデバイスのメディアライブラリから画像を選択する方法を学びます。
1
expo-image-picker をインストールする
expo-image-picker ライブラリをインストールするには、ターミナルで Ctrl + C を押して開発サーバーを停止してから、次のコマンドを実行します。
- npx expo install expo-image-pickernpx expo install コマンドは、ライブラリをインストールし、package.json のプロジェクトの依存関係に追加します。
ヒント: プロジェクトに新しいライブラリをインストールするときは、ターミナルで Ctrl + C を押して開発サーバーを停止してから、インストールコマンドを実行します。インストールが完了したら、npx expo startを実行して開発サーバーを再起動します。
2
デバイスのメディアライブラリから画像を選択する
expo-image-picker は、デバイスのメディアライブラリから画像や動画を選択するためのシステム UI を表示する launchImageLibraryAsync() メソッドを提供します。前の章で作成した primary テーマのボタンを使ってデバイスのメディアライブラリから画像を選択し、この機能を実装するためにデバイスの画像ライブラリを起動する関数を作成します。
app/(tabs)/index.tsx で expo-image-picker ライブラリをインポートし、Index コンポーネント内に pickImageAsync() 関数を作成します。
// ...rest of the import statements remain unchanged import * as ImagePicker from 'expo-image-picker'; export default function Index() { const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, quality: 1, }); if (!result.canceled) { console.log(result); } else { alert('You did not select any image.'); } }; // ...rest of the code remains same }
上記のコードが何をしているのか確認しましょう。
launchImageLibraryAsync()は、さまざまなオプションを指定するためのオブジェクトを受け取ります。このオブジェクトはImagePickerOptionsオブジェクトで、メソッドを呼び出すときに渡します。allowsEditingをtrueに設定すると、Android と iOS では選択時に画像をトリミングできます。
3
ボタンコンポーネントを更新する
primary ボタンを押したときに、Button コンポーネントから pickImageAsync() 関数を呼び出します。components/Button.tsx で Button コンポーネントの onPress プロパティを更新します。
import { StyleSheet, View, Pressable, Text } from 'react-native'; import FontAwesome from '@expo/vector-icons/FontAwesome'; type Props = { label: string; theme?: 'primary'; onPress?: () => void; }; export default function Button({ label, theme, onPress }: Props) { if (theme === 'primary') { return ( <View style={[ styles.buttonContainer, { borderWidth: 4, borderColor: '#ffd33d', borderRadius: 18 }, ]}> <Pressable style={[styles.button, { backgroundColor: '#fff' }]} onPress={onPress}> <FontAwesome name="picture-o" size={18} color="#25292e" style={styles.buttonIcon} /> <Text style={[styles.buttonLabel, { color: '#25292e' }]}>{label}</Text> </Pressable> </View> ); } 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', }, buttonIcon: { paddingRight: 8, }, buttonLabel: { color: '#fff', fontSize: 16, }, });
app/(tabs)/index.tsx で、1 つ目の <Button> の onPress プロパティに pickImageAsync() 関数を追加します。
import { View, StyleSheet } from 'react-native'; import * as ImagePicker from 'expo-image-picker'; import Button from '@/components/Button'; import ImageViewer from '@/components/ImageViewer'; const PlaceholderImage = require('@/assets/images/background-image.png'); export default function Index() { const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, quality: 1, }); if (!result.canceled) { console.log(result); } else { alert('You did not select any image.'); } }; return ( <View style={styles.container}> <View style={styles.imageContainer}> <ImageViewer imgSource={PlaceholderImage} /> </View> <View style={styles.footerContainer}> <Button theme="primary" label="Choose a photo" onPress={pickImageAsync} /> <Button label="Use this photo" /> </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', alignItems: 'center', }, imageContainer: { flex: 1, }, footerContainer: { flex: 1 / 3, alignItems: 'center', }, });
pickImageAsync() 関数は ImagePicker.launchImageLibraryAsync() を呼び出し、その結果を処理します。launchImageLibraryAsync() メソッドは、選択された画像に関する情報を含むオブジェクトを返します。
result オブジェクトとそのプロパティの例を次に示します。
{ "assets": [ { "assetId": null, "base64": null, "duration": null, "exif": null, "fileName": "ea574eaa-f332-44a7-85b7-99704c22b402.jpeg", "fileSize": 4513577, "height": 4570, "mimeType": "image/jpeg", "rotation": null, "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FStickerSmash-13f21121-fc9d-4ec6-bf89-bf7d6165eb69/ImagePicker/ea574eaa-f332-44a7-85b7-99704c22b402.jpeg", "width": 2854 } ], "canceled": false }
{ "assets": [ { "assetId": "99D53A1F-FEEF-40E1-8BB3-7DD55A43C8B7/L0/001", "base64": null, "duration": null, "exif": null, "fileName": "IMG_0004.JPG", "fileSize": 2548364, "height": 1669, "mimeType": "image/jpeg", "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FStickerSmash-13f21121-fc9d-4ec6-bf89-bf7d6165eb69/ImagePicker/ea574eaa-f332-44a7-85b7-99704c22b402.jpeg", "width": 1668 } ], "canceled": false }
{ "assets": [ { "fileName": "some-image.png", "height": 720, "mimeType": "image/png", "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAA" } ], "canceled": false }
4
選択した画像を使用する
result オブジェクトには assets 配列があり、その中に選択された画像の uri が含まれています。この値を画像ピッカーから取得して、選択された画像をアプリに表示します。
app/(tabs)/index.tsx ファイルを変更します。
- React の
useStateフックを使って、selectedImageという状態変数を宣言します。この状態変数は選択された画像の URI を保持するために使います。 pickImageAsync()関数を更新して、画像の URI をselectedImage状態変数に保存します。selectedImageをプロパティとしてImageViewerコンポーネントに渡します。
import { View, StyleSheet } from 'react-native'; import * as ImagePicker from 'expo-image-picker'; import { useState } from 'react'; import Button from '@/components/Button'; import ImageViewer from '@/components/ImageViewer'; const PlaceholderImage = require('@/assets/images/background-image.png'); export default function Index() { const [selectedImage, setSelectedImage] = useState<string | undefined>(undefined); const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], 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 imgSource={PlaceholderImage} selectedImage={selectedImage} /> </View> <View style={styles.footerContainer}> <Button theme="primary" label="Choose a photo" onPress={pickImageAsync} /> <Button label="Use this photo" /> </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', alignItems: 'center', }, imageContainer: { flex: 1, }, footerContainer: { flex: 1 / 3, alignItems: 'center', }, });
プレースホルダー画像の代わりに選択された画像を表示するために、selectedImage プロパティを ImageViewer コンポーネントに渡します。
- components/ImageViewer.tsx ファイルを変更して、
selectedImageプロパティを受け取れるようにします。 - 画像のソースが長くなっているので、
imageSourceという別の変数に切り出します。 Imageコンポーネントのsourceプロパティの値としてimageSourceを渡します。
import { ImageSourcePropType, StyleSheet } from 'react-native'; import { Image } from 'expo-image'; type Props = { imgSource: ImageSourcePropType; selectedImage?: string; }; export default function ImageViewer({ imgSource, selectedImage }: Props) { const imageSource = selectedImage ? { uri: selectedImage } : imgSource; return <Image source={imageSource} style={styles.image} />; } const styles = StyleSheet.create({ image: { width: 320, height: 440, borderRadius: 18, }, });
上記のスニペットでは、Image コンポーネントは条件演算子を使って画像のソースを読み込みます。選択された画像は、プレースホルダー画像のようなローカルアセットではなく、uri 文字列 です。
アプリの状態を確認してみましょう。
このチュートリアルのサンプルアプリで使用されている画像は Unsplash から取得しました。
まとめ
第 4 章:画像ピッカーを使用する
デバイスのメディアライブラリから画像を選択する機能の追加が完了しました。
次の章では、絵文字ピッカーのモーダルコンポーネントを作成する方法を学びます。