画像を参考に次のコードを追加してください
TextEditingController nameController = TextEditingController();
TextEditingController priceController = TextEditingController();
作成した2つのcontroller
をそれぞれのTextField
にセットします。
次のコードを画像のように追加してください
controller: nameController,
controller: priceController,
これでTextField
をcontroller
の支配下に置くことができました。
今回のアプリで管理したいデータは、欲しいものの
「名前」と「金額」
の二つです。今から「名前」と「金額」をワンセットで保存していくためのユニットを作成します。
(ユニット=ひとかたまり、最小単位)
次のコードはGoodsInfo
クラスの定義です。このコードを画像の場所に追加してGoodsInfo
クラスを作成してください。
class GoodsInfo {
GoodsInfo(this.name, this.price);
String name;
int price;
}
Class(クラス)について説明します!
クラスとは、変数(ここでは、名前や金額のこと、このアプリで扱うデータたち)や、
メソッド(機能のこと、変数に対して行う処理)をひとまとめにしたものです。
まずはここについて
その前に、前提知識として変数とデータ型の確認をします
文字や数字などを入れておくための箱。入れ物、容器。
数学の変数とは全く別物なので頭を新しくしてください。
変数に入る値がどんな値か定義するためのもの。
例)
String型=文字列
int型=数字
String name;
このコードが意味するのは、
「文字列(String
)が入る箱をつくった。その箱のことをname
と呼ぶ」ということです。
「String
型の変数name
を定義した」とも言います。
int price;
この一文も同じように考えて、
「数字(int
)が入る箱を作った。その箱のことはprice
と呼ぶ。」
ということです。
つまりGoodsInfo
クラスは、name
とprice
という二つの変数をもったクラスということになります。
クラスというまとまりの中に2つの名前の付いた引き出しがあるようなイメージです!
次はこの一文について
この一文はコンストラクタ
と呼ばれる処理で、このクラスの初期化をしている部分になります。
今日は、この一文は「アプリに必要なもの」くらいに考えてもらえば大丈夫です。
ここからの行程を説明します。
欲しい物のデータ(GoodsInfo
クラス)をList
に保存し、そのList
をUI作成で作った
リスト部分に反映させます。
List
(配列)とは、データの保存庫の様なものです。
上の図のように、データを保存することのできる小部屋がいくつも並んだものがList
になります。
この小部屋には番号がついています。先頭の部屋から
0, 1, 2, 3, 4, ・・・
となっていて、この番号のことをindex
と言います。
完成時のイメージとしては、この小部屋ひとつひとつにGoodsInfo
を収納していく感じです。
ほしいものひとつ分 = 小部屋に収納されたGoodsInfo
となるからです。
このList
では、0番目の部屋に入っているGoodsInfo
と2番目の部屋に入っているGoodsInfo
は、中の引き出し(変数)のデータが違っていることがあると思います。
例えば、0番目のGoodsInfo
クラスは、name
がApple Watch
で、price
が25000
しかし、2番めのGoodsInfo
クラスは、name
がサンダル
で、price
が3000
といった具合です。
これは、先程作成したGoodsInfo
クラスのコピーを作成して使うことで可能になります。そのコピーの中の変数であるname
とprice
に欲しいものの値を当てはめてみましょう。
画像を参考に次のコードを追加してください。
GoodsInfo _goodsInfo = GoodsInfo(
nameController.text,
priceController.text,
);
これでGoodsInfo
クラスから、_goodsInfo
というコピーを作成しました。この行程のことを「クラスをインスタンス(オブジェクト)化する」と言います。
このインスタンス化の考え方は、プログラミングを学ぶ中で、悩むことが多いポイントと言われています。ここでは、はっきりと理解できなくても大丈夫です。
実はクラスというのは設計図のようなもので、実体化(コピーを作る)しないと使えないのです。
おや?
priceController.text,
に赤い波線が出ています。エラーですね。
これは、「int
型の変数price
に、String
型の値であるpriceController.text
を代入しようとしている」ことが原因です。
ここで、前に説明したデータ型が関係してきます。
int
型(数字型)の変数には、int
のデータしか格納することができません。
TextField
に入力された値はそれが数字であってもString
型として扱われる仕様になっているので、そのまま代入するとデータ型が違います
というエラーが出ます。
データ型を変換させます。
エラーの出ている行を次のように書き換えてください。
このように書くとString
型をint
型に変換することができます!
int.parse(priceController.text),
これで、保存ボタンがタップされた時に
「その時TextField
に入力されているname
とprice
を初期値として_goodsInfo
を作成する」
ということが行われます。
ここまでの工程で、「名前」と「金額」の情報を持つ_goodsInfo
を作成することができました。欲しいものと金額をTextField
に入力し保存ボタンをタップすると新しい_goodsInfo
が作成されます。
_goodsInfo
たちが入るList
を作成してデータを管理しましょう。
画像を参考に次のコードを追加してください。GoodsInfo
型が入る配列goodsInfoList
を作成するコードです。
List<GoodsInfo> goodsInfoList = [];
次は、保存ボタンを押したらgoodsInfoList
に_goodsInfo
が追加される様にします。
保存ボタンの { } 内に
「_goodsInfo
をgoodsInfoList
に追加する処理」を書きます。
こうすることにより、保存ボタンが押されるたびに_goodsInfo
がgoodsInfoList
に追加されます。
goodsInfoList.add(_goodsInfo);
入力した情報をList
に保存することができるようになりました。
はじめにUI(見た目)を作成したときは、リスト部分の表示内容を
で固定にしていました。なので今からgoodsInfoList
のデータで欲しい物リストが表示されるように変更します。
ListView
が入力されているところを見てください。
まずは画像のところを書き換えます。itemCount
はリストに何件表示するのかを設定する場所です。
今は20
で固定になっています。
itemCount
を画像のように変更してください。
length
は長さという意味ですが、 この場合はList
が持っている要素の数を表しています。
List
の小部屋が何個埋まっているか教えてくれるイメージです。
goodsInfoList.length
次はここです。ここは名前と金額を表示している部分です。
今はSwitch
と25000
で固定になっています。
それぞれ画像を参考に書き換えてください。このように指定することで、goodsInfoList
の要素の数だけリストを出力してくれます。
goodsInfoList[index].name
goodsInfoList[index].price.toString()
これで、goodInfoList
の内容でリスト部分が表示されるようになりました!
次に保存ボタンElevatedButton
のonPressed
の中に次のコードを追加してください。
setState(() {
});
これはsetState
と言い、「現在の状態で画面を再描画する」という処理を行います。
今表示されている画面は、goodsInfoList
に新しい_goodsInfo
が追加される「前」のものです。
なので、空のgoodsInfoList
でリスト部分が作られているため何も表示されません。
_goodsInfo
をgoodsInfoList
に追加した後に画面を再描画することで、
新たに追加した_goodsInfo
が反映されたリストを表示することができます。
では、なんでもいいので欲しいもの
を入力して保存ボタンを押してみましょう。
保存されました!
でも、保存ボタンを押したのにTextField
に値が残っていて使いにくいですね。
次は保存を押したタイミングでTextField
の中身をクリアになるようにします。
「保存ボタンがタップされた時にTextField
の中身をクリアにする」が実現したいことです。
保存ボタンがタップされた時の処理はonPressed
の{ }の中に記述するんでしたね。
{ } 内に、TextField
の中身をクリアにするという処理を書きます。
次のコードを追加してください。
nameController.clear();
priceController.clear();
ホットリロードで反映させてからシミュレーターで動きを確認しましょう。
保存ボタンを押したあとに、TextField
がクリアになりましたね。
最後に、合計金額を表示させる処理を作ります。 あと少しです!頑張りましょう💪
まずは合計金額を入れておくための変数を用意します。
画像を参考にint
型の変数total
を定義してください。初期値として0
を入れておきます。
int total = 0;
次に一番下の合計金額表示の部分を変更します。今は100
で固定になっていますね。
作成した変数total
の値が表示されるようにするため、下の画像のように書き換えます。
total
はint
型の変数なので、Text
で表示するためには .toStirng()
でString
型に変換する必要があります。
total.toString()
ホットリロードで反映してみましょう。0円になりました!
ただ、total
の中身が初期値の0
になっていますね。
保存ボタンが押されたタイミングで金額が加算されていくようにします。
保存ボタンが押された時の処理なので、ElevantedButton
のonPressed
の { } 内に書きます。
画像を参考に一行コードを書いてください。
total = total + _goodsInfo.price;
このコードは「total
にtotal + _goodsInfo.price
を代入する」という意味です。
このような書き方をすることで、合計金額に欲しいものの金額が追加されていきます。 ホットリロードでシミュレーターに反映して動きを確かめてください。 おお!ちゃんと合計金額が計算されて動的に表示されています!感動!
TextField
にフォーカスを当ててcommand + k
を押してください。
キーボードが出てきましたね。
ただ、金額のTextField
にフォーカスが当たっている時でも言語のキーボードが表示されてしまっています。
金額の方は数字キーボードを表示したいので今からそれをやります。 画像を参考に以下のコードを追加してください。
keyboardType: TextInputType.number,
ホットリロードでシミュレーターに反映して、動きを確かめてください。 おお!数字のキーボードが表示されていますね!
以上で欲しいもの記録アプリは完成です🎉 ボタンのレイアウトを変えたり、背景に色をつけたり、色々と遊んでみてください!