React Native Paperとは
GoogleのMaterial Designガイドラインに基づいた
React Native用のUIコンポーネントライブラリです。
美しく一貫性のあるデザインを簡単に実装できるよう設計されている。
React Nativeの標準コンポーネントとの違い
標準コンポーネント
- 基本的な機能のみを提供
- デザインは最小限でプラットフォーム固有の見た目
- UIのスタイリングは全て自分で行う
React Native Paper
- デザイン済の高機能コンポーネント
- Material Designガイドラインに従った一貫したデザイン
- テーマ機能によるアプリ全体の色や字体の統一
- アニメーションや状態管理が組み込み済み
React Native Paperを使うメリット
開発の効率化:
1つのコードベースでiOSとAndroidの両方に対応できるのと、
デザイン済のコンポーネントを使うことでUI開発の時間が大幅に短縮される。
デザインの一貫性:
すべてのコンポーネントが Material Design に従っているため、
統一感のあるデザインが簡単に実現できます
テーマ機能:
アプリ全体のカラーテーマやフォントを簡単に変更できる。
ダークモード対応:
標準でダークモードをサポートしている。
アクセシビリティ
アクセシビリティ機能が標準で組み込まれている。
利用準備
1.インストール
npm install react-native-paper
2.開発環境
Expo: 52.0.46
react-native: 0.76.9
react-native-paoer: 5.13.1
3.レイアウトコンポーネント追記
_layout.tsx
const Layout = () => {
return (
<PaperProvider>
<Stack screenOptions={{ headerShown: false }} />
</PaperProvider>
)
}
export default Layout
4.実装例
paperui_sample.tsx
import { router } from "expo-router"
import { StatusBar } from "expo-status-bar"
import { useState } from "react"
import { StyleSheet, View } from "react-native"
import { ScrollView } from "react-native-gesture-handler"
import { ActivityIndicator, Appbar, Avatar, Banner, Button, Checkbox, Divider, RadioButton, SegmentedButtons, Snackbar, Switch, Text, TextInput, useTheme } from "react-native-paper"
const PaperUISample = () => {
const theme = useTheme()
const [text, setText] = useState('')
const [isLoading, setIsLoading] = useState(false)
const [switchValue, setSwitchValue] = useState(false)
const [checkboxStatus, setCheckboxStatus] = useState(false)
const [radioValue, setRadioValue] = useState('')
const [segmentValue, setSegmentValue] = useState('')
const [snackbarVisible, setSnackbarVisible] = useState(false)
const [bannerVisible, setBannerVisible] = useState(false)
return (
<View style={styles.container}>
<StatusBar style="auto" />
{/* 画面上部のナビゲーションバー */}
{/* BackActionは戻るボタン */}
{/* Contentはタイトル(画面名など)を表示 */}
<Appbar.Header>
<Appbar.BackAction onPress={() => router.back()} />
<Appbar.Content title="UI Sample" />
</Appbar.Header>
{/* バナー表示 */}
{/* visible:表示/非表示制御、actions:ボタンの配列、icon:バナーに表示するアイコン */}
<Banner
visible={bannerVisible}
actions={[
{
label: '確認',
onPress: () => setBannerVisible(false)
},
{
label: '閉じる',
onPress: () => setBannerVisible(false)
}
]}
icon={() => (
<Avatar.Icon size={40} icon='alert' />
)}
>
バナーを開くとこちらの情報が表示されます。
</Banner>
{isLoading ? (
<View style={styles.loadingContainer}>
{/* インジケーター */}
{/* size:'small' or 'large'で指定、animating:アニメーション有無、color:インジケーターの色 */}
<ActivityIndicator size="large" animating={true} color={theme.colors.primary} />
<Text style={[styles.loadingText, { color: theme.colors.primary }]} variant='labelLarge' >loading...</Text>
<Button
mode="outlined"
onPress={() => setIsLoading(false)}
>
戻る
</Button>
</View>
) : (
<ScrollView style={styles.scrollView}>
{/* テキスト入力 */}
<View style={styles.section}>
{/* ラベル表示 */}
{/* variant:ラベルのフォントサイズ */}
<Text variant='titleMedium' style={styles.sectionTitle}>
テキスト入力
</Text>
{/* テキスト入力フィールド */}
<TextInput
label='テキスト入力できます'
value={text}
onChangeText={text => setText(text)}
/>
</View>
<Divider style={styles.divider} />
<View style={styles.section}>
<Text variant='titleMedium' style={styles.sectionTitle}>基本コンポーネント</Text>
<View style={styles.row}>
<Text variant='titleMedium'>スイッチ</Text>
{/* on/offを切り替えるスイッチ */}
<Switch
value={switchValue}
onValueChange={() => setSwitchValue(!switchValue)}
/>
</View>
<View style={styles.row}>
<Text variant="titleMedium">チェックボックス</Text>
{/* チェックボックス */}
<Checkbox
status={checkboxStatus ? "checked" : "unchecked"}
onPress={() => setCheckboxStatus(!checkboxStatus)}
/>
</View>
<Text variant='titleMedium' style={styles.sectionTitle} >ラジオボタン</Text>
{/* ラジオボタン */}
{/* Group:ラジオボタングループ化 */}
{/* 各RadioButtonには一意のvalueを指定 */}
<RadioButton.Group
onValueChange={value => setRadioValue(value)}
value={radioValue}
>
<View style={styles.radioContainer}>
<View style={styles.radioRow}>
<RadioButton value="1" />
<Text>Radio 1</Text>
</View>
<View style={styles.radioRow}>
<RadioButton value="2" />
<Text>Radio 2</Text>
</View>
</View>
</RadioButton.Group>
<Text variant='titleMedium' style={styles.sectionTitle}>セグメントボタン</Text>
{/* セグメント選択UI */}
<SegmentedButtons
value={segmentValue}
onValueChange={setSegmentValue}
buttons={[
{ value: 'walk', label: '散歩', icon: 'walk' },
{ value: 'train', label: '電車', icon: 'train' },
{ value: 'car', label: '車', icon: 'car' }
]}
/>
</View>
<Divider style={styles.divider} />
<View style={styles.section}>
<Text variant='titleMedium' style={styles.sectionTitle}>アクション</Text>
{/* ボタン */}
{/* mode: テキスト、塗りつぶし、枠線付きなど */}
<Button
mode='contained'
onPress={() => setIsLoading(true)}
style={styles.button}
>
読み込み開始
</Button>
<Button
mode='contained'
onPress={() => setBannerVisible(true)}
style={styles.button}
>
バナー表示
</Button>
<Button
mode='contained'
onPress={() => setSnackbarVisible(true)}
style={styles.button}
>
スナックバー表示
</Button>
</View>
</ScrollView>
)}
{/* スナックバー */}
{/* visible:表示/非表示を制御、onDismiss:非表示にする時の関数、action:アクションボタン、duration:表示時間(ミリ秒) */}
<Snackbar
visible={snackbarVisible}
onDismiss={() => setSnackbarVisible(!snackbarVisible)}
action={{
label: '閉じる',
onPress: () => setSnackbarVisible(!snackbarVisible)
}}
duration={10000}
>
エラーや正常終了などのメッセージ表示に使います
</Snackbar>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 16
},
loadingText: {
marginVertical: 16
},
scrollView: {
flex: 1,
padding: 16
},
section: {
marginBottom: 16
},
sectionTitle: {
marginBottom: 8
},
divider: {
marginVertical: 16
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 8
},
radioContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
marginBottom: 16
},
radioRow: {
flexDirection: 'row',
alignItems: 'center',
width: '40%'
},
button: {
marginVertical: 8
}
})
export default PaperUISample
実行結果(Androidエミュレータ)
当方の開発環境では、デフォルトカラー黄色で定義しているため、
全般的に黄色メインで画面表示されます。
(デフォルトは紫色になっております。)