質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

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

Q&A

解決済

1回答

870閲覧

FlutterのExpansionPanelListでSetStateが反映しない

RyuHo

総合スコア42

Flutter

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

0グッド

0クリップ

投稿2022/03/25 23:27

Flutterでとあるアプリのアドオンを作れるアプリを開発しています。
そこで、ExpansionPanelListを使用して折り畳み可能なwidgetを作ったのですが、ExpansionPanelListのchildに指定したColumnのchildrenに指定したExpansionPanelでbodyに指定したcolumnのchildrenに指定したwidgetのフィールドの値を変えることができませんでした。
bodyのcolumnのchildにはElevatedButtonを指定していてそのchildのTextから別の配列を参照しています。
ExpansionPanelListの外でSetStateを実行しても配列の値がElevatedButtonのchildのTextの値が変わりません。

Dart

1class addonEditorHome extends StatefulWidget { 2 String addonName; 3 addonEditorHome({required this.addonName}) : super(); 4 5 _addonEditorHomeState createState() => new _addonEditorHomeState(); 6} 7 8class _addonEditorHomeState extends State<addonEditorHome> { 9 bool itemExpanded = false; 10 bool blockExpanded = false; 11 String itemText = "アイテム"; 12 String blockText = "ブロック"; 13 int itemCount = 0; 14 int blockCount = 0; 15 List<Widget> blockList = []; 16 List<Widget> itemList = []; 17 PreferredSizeWidget? bottomAction = null; 18 List<String> itemIds = [];//こちらで配列を宣言しています。 19 List<Image> itemImageFiles = []; 20 21 void initState() { 22 super.initState(); 23 getObjectsList(); 24 } 25 26 27 Widget build(BuildContext context) { 28 return Scaffold( 29 appBar: AppBar( 30 title: Text(widget.addonName), 31 leading: BackButton( 32 onPressed: backToHome, 33 ), 34 actions: <Widget>[ 35 ], 36 bottom: bottomAction), 37 body: Container( 38 alignment: Alignment.center, 39 child: Padding( 40 padding: EdgeInsets.fromLTRB(150, 100, 200, 150), 41 child: SingleChildScrollView( 42 child: Column(children: [ 43 ExpansionPanelList( 44 expansionCallback: (int index, bool isExpanded) { 45 setState(() { 46 if (index == 0) { 47 itemExpanded = !itemExpanded; 48 } else if (index == 1) { 49 blockExpanded = !blockExpanded; 50 } 51 }); 52 }, 53 children: [ 54 ExpansionPanel( 55 headerBuilder: (BuildContext context, bool isExpanded) { 56 return Container( 57 padding: EdgeInsets.all(8.0), 58 child: Row( 59 children: <Widget>[ 60 Container( 61 child: Image.asset( 62 "assets/images/system_icons/item.png", 63 width: 50, 64 height: 50, 65 ), 66 padding: EdgeInsets.all(5), 67 ), 68 Text( 69 itemText, 70 style: TextStyle( 71 fontSize: 25, 72 ), 73 ) 74 ], 75 ), 76 ); 77 }, 78 body: Column(children: itemList), 79 isExpanded: itemExpanded, 80 ), 81 82 ], 83 ) 84 ])), 85 )), 86 floatingActionButton: FloatingActionButton.extended( 87 onPressed: () => CreateObject(), 88 label: Text("追加"), 89 icon: Icon(Icons.add), 90 ), 91 ); 92 } 93 94 void CreateObject() { 95 Navigator.push( 96 context, 97 MaterialPageRoute( 98 builder: (context) => CreateNewObjectHome(widget.addonName))) 99 .then((value) => loadNewObject(value)); 100 } 101 102 void loadNewObject(List<String>? value) async { 103 if (value != null) { 104 var l = await localPath; 105 if (value[1] == "block") { 106 //省略させていただきます。 107 if (value[1] == "item") { 108 itemCount++; 109 int ic = itemCount; 110 var m = await File(l + 111 "/addons/" + 112 widget.addonName + 113 "/items/" + 114 value[0] + 115 "/data.json") 116 .readAsString(); 117 Map decItem = json.decode(m); 118 var itemInfo = new addonItem.fromJson(decItem); 119 itemIds.add(itemInfo.id); 120 itemImageFiles.add(Image.file( 121 await createPixelImage(l + 122 "/addons/" + 123 widget.addonName + 124 "/items/" + 125 value[0] + 126 "/texture.png"), 127 width: 80, 128 height: 80, 129 )); 130 Widget item = Container( 131 height: 120, 132 padding: EdgeInsets.fromLTRB(0, 10, 0, 10), 133 child: ElevatedButton( 134 child: Row( 135 children: [ 136 Container(child: itemImageFiles[ic - 1]), 137 Text(itemIds[ic - 1], style: TextStyle(fontSize: 25))//<=こちらで配列を参照しています。 138 ], 139 ), 140 onPressed: () => EditItem(itemIds[ic - 1], ic - 1), 141 ), 142 ); 143 setState(() { 144 itemList.add(item); 145 itemText = "アイテム(" + itemCount.toString() + ")"; 146 }); 147 } 148 } 149 } 150 151 void getObjectsList() async { 152 setState(() { 153 bottomAction = PreferredSize( 154 preferredSize: Size.fromHeight(7), 155 child: LinearProgressIndicator( 156 color: Colors.green, 157 minHeight: 7, 158 ), 159 ); 160 }); 161 List<Widget> block_List = <Widget>[]; 162 List<Widget> item_List = <Widget>[]; 163 var l = await localPath; 164 Directory blockdir = 165 Directory(l + "/addons/" + widget.addonName + "/blocks"); 166 Directory itemdir = Directory(l + "/addons/" + widget.addonName + "/items"); 167 //省略させていただきます。 168 await for (var item in itemdir.list(recursive: false, followLinks: false)) { 169 itemCount++; 170 int ic = itemCount; 171 var m = await File(item.path + "/data.json").readAsString(); 172 Map decItem = json.decode(m); 173 var itemInfo = new addonItem.fromJson(decItem); 174 itemIds.add(itemInfo.id); 175 itemImageFiles.add(Image.file( 176 await createPixelImage(l + 177 "/addons/" + 178 widget.addonName + 179 "/items/" + 180 itemIds[ic - 1] + 181 "/texture.png"), 182 width: 80, 183 height: 80, 184 )); 185 Widget itemContainer = Container( 186 height: 120, 187 padding: EdgeInsets.fromLTRB(0, 10, 0, 10), 188 child: ElevatedButton( 189 child: Row( 190 children: [ 191 Container(child: itemImageFiles[ic - 1]), 192 Text(itemIds[ic - 1], style: TextStyle(fontSize: 25)) 193 ], 194 ), 195 onPressed: () => EditItem(itemIds[ic - 1], ic - 1)), 196 ); 197 item_List.add(itemContainer); 198 } 199 setState(() { 200 bottomAction = null; 201 blockText = "ブロック(" + blockCount.toString() + ")"; 202 blockList = block_List; 203 itemText = "アイテム(" + itemCount.toString() + ")"; 204 itemList = item_List; 205 }); 206 } 207 208 void EditItem(String id, int index) { 209 Navigator.push( 210 context, 211 MaterialPageRoute( 212 builder: (context) => 213 ItemInspectorHome(id, index, widget.addonName))) 214 .then((value) => {afterEditItem(value, index)}); 215 } 216 217 void afterEditItem(List<String?> value, int ind) { 218 if (value[0] != "") { 219 setState(() { 220 itemIds[ind] = value[0] as String;//ここで配列の値を変更しています。しかし、変更がElevatedButtonに反映しません。 221 }); 222 } 223 } 224}

長くなりましたが、ずっとここで行き詰っていました。どんなことでも構いませんのでわかる方がいらっしゃれば回答していただけると大変助けになります。

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

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

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

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

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

guest

回答1

0

ベストアンサー

itemListの中身の再構築が走ってないのでは。
(個人的にsetStateはbuildを再実行させる仕組みと思ってます。)

別途itemListの中身を作成するか、buildメソッド内で作成するようにするか、もしくは何らかの状態管理機能を用いて、itemIdsとElevatedButton内のTextを紐づけて更新するようにする必要があると思います。

投稿2022/03/26 02:52

ta.fu

総合スコア1667

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

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

RyuHo

2022/03/26 08:15

回答していただきありがとうございます! Flutter初心者ですのですみません。どのように直せばよいのか教えていただけますか?
ta.fu

2022/03/26 09:42

回答の編集ができなかったのでこちら側に。 ---- 提示されたコードが長いのと、そのままではビルドできないものだったので、とりあえず変更方法の概略だけ。 getObjectsList()内でitemIds[ic - 1]を用いてイメージとそのイメージを使ってElevatedButtonのコンテナ群を作成している処理を切り出し、itemListを再作成する関数を作成します。 その関数をbuild()メソッドの中のreturn Scaffoldの前にいれれば、とりあえずは再作成はされると思います。 ただこの方法はパフォーマンスに問題が出ると思います。 パフォーマンスに有利な方法としては、StringからイメージとElevatedButtonのウィジェット1個を作成するクラスをStatefulWidgetの派生で作成し、そちらにEditItem以下の処理を委譲してしまう。 addonEditorHome側ではitemIdsのforループで上のウィジェット群を作成しbody: Column(children:に渡す。 こちらだと、再作成対象は1つのElevatedButtonになりますが、addonEditorHomeクラスとの関係をどうするのか、設計の見直しになると思います。
RyuHo

2022/03/27 01:41

ありがとうございます! 私はもうパフォーマンスとか気にしないので前者を選択しました。 回答していただき本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問