🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

コンストラクタ

オブジェクト指向言語において、オブジェクトを生成時に呼び出され、データの初期化などを行なう関数・メソッドのことである。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

1回答

4711閲覧

【Flutter】statefulWidgetクラスのコンストラクタで初期化されたメンバ変数をstateとして動的に管理したい

kurimaron7

総合スコア14

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

コンストラクタ

オブジェクト指向言語において、オブジェクトを生成時に呼び出され、データの初期化などを行なう関数・メソッドのことである。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2020/12/08 12:36

前提・実現したいこと

親クラスのメンバ変数で定義したリストデータをもとに、独自定義のクラス(StatefulWidget)をリスト表示したいです。
リンクにサンプルコードを記載しています。(下記に同じコード記載しています)
そもそも、この実装が不適切である場合や、推奨される実装があればご教授いただけますと幸いです。

List<CounterItem> _counterItems = List<CounterItem>.generate(30, (index) => CounterItem(0)); 〜〜〜〜〜〜〜〜〜〜 省略 〜〜〜〜〜〜〜〜〜〜 itemBuilder: (context, index) { // 1要素ずつ、レンダリングしていく return _counterItems[index]; },

上記 Listデータの各要素を、ListViewの項目にしたいと考えております。

発生している問題・エラーメッセージ

サンプルコードでは、CouterItemのコンストラクタで初期化した値をstateクラスでinitState()することで動的に値を変更しています。ですが、この実装だとコンストラクタで渡された値とは実体が異なるため、_MyHomePageStateListView.builderが実行される(スクロールする)ごとに値が消えてしまいます。
当初は、CounterItemのメンバ変数(score)をfinal修飾子を付けずに、widget.scoreで値にアクセスするように実装していました。この実装の場合は、値をもとのリストが保持するため再描画されても値を保持できてました。しかし、statefulWidgetは@immutableアノテーションで定義するようにワーニングが表示されるので、別の実装庵を考えおります。

該当のソースコード

dart

1import 'package:flutter/material.dart'; 2 3void main() { 4 runApp(MyApp()); 5} 6 7class MyApp extends StatelessWidget { 8 9 Widget build(BuildContext context) { 10 return MaterialApp( 11 title: 'Flutter Demo', 12 home: MyHomePage(title: 'Flutter Demo Home Page'), 13 ); 14 } 15} 16 17class MyHomePage extends StatefulWidget { 18 MyHomePage({Key key, this.title}) : super(key: key); 19 final String title; 20 21 22 _MyHomePageState createState() => _MyHomePageState(); 23} 24 25class _MyHomePageState extends State<MyHomePage> { 26 // 状態も含め管理するデータを準備する 27 List<CounterItem> _counterItems = 28 List<CounterItem>.generate(30, (index) => CounterItem(0)); 29 30 31 Widget build(BuildContext context) { 32 return Scaffold( 33 appBar: AppBar( 34 title: Text(widget.title), 35 ), 36// 推測だが、builder関数は、スクロールされるたびに表示画面内の要素を再度レンダリングしているので、scoreが保持されない。 37 body: ListView.builder( 38 itemCount: _counterItems.length, 39 itemBuilder: (context, index) { 40 // 1要素ずつ、レンダリングしていく 41 return _counterItems[index]; 42 }, 43 ), 44 ); 45 } 46} 47 48// 以下のクラスを別ファイルに分割して、パーツとして管理したい 49class CounterItem extends StatefulWidget { 50 CounterItem(this.score); 51 final int score; 52 53 _CounterItemState createState() => _CounterItemState(); 54} 55 56class _CounterItemState extends State<CounterItem> { 57 int _score; 58 59 60 void initState() { 61 super.initState(); 62 _score = widget.score; // 値渡しすることになるので、大元のListデータに反映できない 63 } 64 65 66 Widget build(BuildContext context) { 67 return Container( 68 decoration: BoxDecoration( 69 border: Border(bottom: BorderSide(width: 1.0, color: Colors.grey))), 70 child: ListTile( 71 leading: ElevatedButton( 72 child: Text('カウント アップ'), 73 onPressed: () { 74 setState(() { 75 _score++; 76 // widget.score++; 77 }); 78 }, 79 ), 80 title: Text( 81 '$_score', 82 // '${widget.score}', 83 style: TextStyle(color: Colors.black, fontSize: 18.0), 84 ), 85 ), 86 ); 87 } 88}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

値の保持はListViewitem側で行うより、その保持側(上位のState)で行うと良いかと思います。
例えば以下のような形で値の保持自体はできそうです。

dart

1import 'package:flutter/material.dart'; 2 3void main() { 4 runApp(MyApp()); 5} 6 7class MyApp extends StatelessWidget { 8 9 Widget build(BuildContext context) { 10 return MaterialApp( 11 title: 'Flutter Demo', 12 home: MyHomePage(title: 'Flutter Demo Home Page'), 13 ); 14 } 15} 16 17class MyHomePage extends StatefulWidget { 18 MyHomePage({Key key, this.title}) : super(key: key); 19 final String title; 20 21 22 _MyHomePageState createState() => _MyHomePageState(); 23} 24 25class _MyHomePageState extends State<MyHomePage> { 26 final _listItems = List<int>.generate(30, (_) => 0); 27 28 29 Widget build(BuildContext context) { 30 return Scaffold( 31 appBar: AppBar( 32 title: Text(widget.title), 33 ), 34 body: ListView.builder( 35 itemCount: _listItems.length, 36 itemBuilder: (context, index) { 37 return CounterItem( 38 score: _listItems[index], 39 onPressed: () => setState(() => _listItems[index]++), 40 ); 41 }, 42 ), 43 ); 44 } 45} 46 47class CounterItem extends StatelessWidget { 48 CounterItem({this.score, this.onPressed}); 49 final int score; 50 final VoidCallback onPressed; 51 52 53 Widget build(BuildContext context) { 54 return Container( 55 decoration: BoxDecoration( 56 border: Border(bottom: BorderSide(width: 1.0, color: Colors.grey))), 57 child: ListTile( 58 leading: ElevatedButton( 59 child: Text('カウント アップ'), 60 onPressed: onPressed, 61 ), 62 title: Text( 63 '$score', 64 // '${widget.score}', 65 style: TextStyle(color: Colors.black, fontSize: 18.0), 66 ), 67 ), 68 ); 69 } 70} 71

投稿2020/12/10 03:28

編集2020/12/10 03:36
KyoheiG3

総合スコア59

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kurimaron7

2020/12/26 08:42

回答ありがとうございます。 やはり、コールバックで対応するのが良さそうですかね。 しかし、コールバックメソッドが大量にある場合など可読性などが悪くなりそうだと思うのですが、どうなのでしょうか? また、Providerなどのアーキテクチャを活用していくのが良いのでしょうか?
KyoheiG3

2021/01/04 02:33

回答遅くなりました。 コールバックが大量にあるとはどのような状況でしょうか? 単純なリストのアイテムだとせいぜい数個程度だとは思いますが、2~3個程度までであれば上記コードのようなクロージャでのハンドリングで良いかと思います。 可読性などを考慮する場合はイベントの種類ごとにクロージャをまとめて、そのクロージャの引数としてコールバックイベント専用の`enum`やクラスを用意しイベントをハンドリングするなどである程度対応できそうです。が、結局はどこかに分岐やらが必要になるかと。 単純なボタンやリストのタップのイベントのハンドリングのためだけに`Provider`などを導入するのは少々過剰かと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問