🐥
ネイティブアプリ開発日記(4/100)入力機能の改善
前回はこちら
■前回作成した家計簿アプリの機能
●支出の金額、カテゴリ、年月日を登録できる ←今回の改善対象
●登録した支出の一覧を参照できる
●月毎の支出の合計を参照できる
■今回の改善
支出の金額、カテゴリ、年月日を登録する際の入力機能を改善する。
具体的には、
- 年月日
- 自由記述ではなくカレンダーから選択できるようにする。デフォルトで現在年月日が入る
- 金額
- 自由記述ではなくテンキーを用いて入力できるようにする
- カテゴリ
- 自由記述ではなく選択肢から選択できるようにする
以下のイメージ
入力欄全体

年月日の選択

金額の入力

カテゴリの選択

実装面の学び1. カレンダー入力
- カレンダーの表示
- @react-native-community/datetimepickerの活用
- DateTimePicker で display='spinner'を選択
- 表示/非表示の切り替え
- const [showPicker, setShowPicker] = useState(false) で状態を定義
- 「日付を選択」ボタンを押下すると表示
- <Button title='日付を選択' onPress={() => setShowPicker(true)} />
- 日付を選択し「OK」を押下すると非表示
- <TouchableOpacity onPress={() => setShowPicker(false)}>
- TouchableOpacity
- タップしたときに 透明度(opacity)を下げて、押されたことを視覚的に示す
AddExpenseScreen.js
import DateTimePicker from '@react-native-community/datetimepicker';
const [showPicker, setShowPicker] = useState(false);
(略)
<Button title='日付を選択' onPress={() => setShowPicker(true)} />
{showPicker && (
<View>
<DateTimePicker
value={date}
mode="date"
display='spinner'
onChange={(date) => setDate(date)}
/>
{Platform.OS === 'ios' && (
<TouchableOpacity onPress={() => setShowPicker(false)}>
<Text>OK</Text>
</TouchableOpacity>
)}
</View>
)}
実装面の学び2. テンキー入力
- 支出金額の管理
- const [amount, setAmount] = useState('')で状態を定義
- テンキー入力
- TouchableOpacityを用いて、愚直に1,2,...,9,0を表示
- key={digit} onPress={() => handlePress(digit)} で押下を検出
- handlePressは setAmount((prev) => prev + digit) で状態を更新
- 入力した数値の修正
- TouchableOpacity onPress={handleDelete} で押下を検出
- handleDeleteは setAmount((prev) => prev.slice(0, -1)) で状態を更新
- 入力した数値の確定
- TouchableOpacity onPress={() => onConfirm(Number(amount))} で押下を検出
- onConfirm は呼び出し元(親)から渡される関数(後述)
utils/numberInput.js
export default function AmountInputPad({ onConfirm }) {
const [amount, setAmount] = useState('');
// 数字ボタン(0〜9)が押されたとき、金額の文字列にその数字を追加する。最大9桁とした
const handlePress = (digit) => {
if (amount.length < 9) {
setAmount((prev) => prev + digit);
}
};
// 削除ボタンが押された時、一番右の一桁を削除する
const handleDelete = () => {
setAmount((prev) => prev.slice(0, -1));
};
// onConfirm は親(呼び出し元)で指定するコールバック関数
return (
<View>
<Text>¥{amount || '0'}</Text>
<View>
{['1','2', '3', '4', '5', '6', '7', '8', '9', '0'].map((digit) => (
<TouchableOpacity key={digit} onPress={() => handlePress(digit)}>
<Text>{digit}</Text>
</TouchableOpacity>
))}
<TouchableOpacity onPress={handleDelete}>
<Text>←</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => onConfirm(Number(amount))}>
<Text>OK</Text>
</TouchableOpacity>
</View>
</View>
);
}
- 親(呼び出し元)
- const [amount, setAmount] = useState('') で状態を定義
- AmountInputPad(子)を呼び出し、onConfirmとして状態の更新関数を渡す
AddExpenseScreen.js
const [amount, setAmount] = useState('');
(略)
<AmountInputPad onConfirm={(value) => setAmount(value)} />
実装面の学び3. 選択肢から選択
- リストから選択するUI
- @react-native-picker/picker の活用
- Picker タグ内で、Picker.Itemで一つずつ表示
- {リスト.map((要素) => (<Picker.Item key={要素.value} /> ))}
- 選択した値で更新する処理
- const [category, setCategory] = useState('-') で状態を定義
- onValueChange={(itemValue) => setCategory(itemValue)} で更新
AddExpenseScreen.js
import { Picker } from '@react-native-picker/picker';
import { categories } from '../parameters/categories';
(略)
const [category, setCategory] = useState('-');
(略)
<View>
<Picker
selectedValue={category}
onValueChange={(itemValue) => setCategory(itemValue)}
>
{categories.map((cat) => (
<Picker.Item key={cat.value} label={cat.label} value={cat.value} />
))}
</Picker>
</View>
- 選択肢の外部定義
parameters/categories.js
export const categories = [
{ label: '-', value: '-' }, // 未入力用
{ label: '食費', value: '食費' },
{ label: '交通費', value: '交通費' },
(略)
]
Discussion