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

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

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

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

Dart

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

Q&A

解決済

2回答

2116閲覧

Flutter: CheckboxのonChangedプロパティが勝手に実行されてしまう。

massanmesu

総合スコア36

Flutter

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

Dart

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

0グッド

0クリップ

投稿2021/07/15 06:08

ListViewの中に下の画像のようなWidgetがあります。

イメージ説明
チェックボタンがチェックされると文字の真ん中に線が引かれるようにしたいです。
イメージ説明

ListTileのtrailingにChechboxのカスタムWidgetを指定し、引数にチェックボタンの状態を表すbool値と、そのbool値を反映する関数を渡しています。

import 'package:flutter/material.dart'; class TaskTile extends StatefulWidget { const TaskTile({ Key? key, }) : super(key: key); @override State<TaskTile> createState() => _TaskTileState(); } class _TaskTileState extends State<TaskTile> { bool isChecked = false; // チェックボタンのBool値を反映する void checkboxCallback(bool checkboxState) { setState(() { isChecked = checkboxState; }); } @override Widget build(BuildContext context) { return ListTile( title: Text( 'This is a task', style: TextStyle( decoration: isChecked ? TextDecoration.lineThrough : null), ), // カスタムチェックボックス trailing: TaskCheckbox( checkboxState: isChecked, toggleCheckboxState: checkboxCallback, // 関数そのものを渡す ), ); } } class TaskCheckbox extends StatelessWidget { TaskCheckbox({this.checkboxState, this.toggleCheckboxState}); final bool? checkboxState; final Function? toggleCheckboxState; @override Widget build(BuildContext context) { return Checkbox( value: checkboxState!, // チェック時に関数実行 onChanged: toggleCheckboxState!(checkboxState!), ); } }

この状態で動かすと膨大なエラー分が発生しました。
以下は一番先頭にあったエラーです。

======== Exception caught by widgets library ======================================================= The following assertion was thrown building TaskCheckbox(dirty): setState() or markNeedsBuild() called during build. This TaskTile widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. The widget on which setState() or markNeedsBuild() was called was: TaskTile state: _TaskTileState#472c8 The widget which was currently being built when the offending call was made was: TaskCheckbox dirty The relevant error-causing widget was: TaskCheckbox file:///Users/kudokoki/AndroidStudioProjects/Flutter/appbrewery/today_flutter/lib/widgets/task_tile.dart:30:17 When the exception was thrown, this was the stack: #0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4298:11) #1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4313:6) #2 State.setState (package:flutter/src/widgets/framework.dart:1108:15) #3 _TaskTileState.checkboxCallback (package:today_flutter/widgets/task_tile.dart:16:5) #4 TaskCheckbox.build (package:today_flutter/widgets/task_tile.dart:49:38) #5 StatelessElement.build (package:flutter/src/widgets/framework.dart:4732:28) #6 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4658:15) #7 Element.rebuild (package:flutter/src/widgets/framework.dart:4348:5) #8 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4636:5) #9 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4631:5) ... Normal element mounting (27 frames) #36 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3666:14) #37 Element.updateChild (package:flutter/src/widgets/framework.dart:3418:18) #38 _ListTileElement._mountChild (package:flutter/src/material/list_tile.dart:1322:31) #39 _ListTileElement.mount (package:flutter/src/material/list_tile.dart:1337:5) ... Normal element mounting (164 frames) (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch) ==================================================================================================== ...

setState()が悪さしてると思い、文字列を出力するだけの処理に変えたところ、なぜかチェックボタンを押していないのに2回実行されてしまいます。

void checkboxCallback(bool checkboxState) { - setState(() { - isChecked = checkboxState; - }); + print('call backed'); }

console

1Performing hot restart... 2Syncing files to device iPhone XR... 3Restarted application in 879ms. 4flutter: call backed 5flutter: call backed

膨大なエラー以前に、なぜ押してもいないチェックボタンの処理が実行(しかも2回)されるのでしょうか?
教材に沿って進めているのですが、そのような解説もなく、エラー文で検索しようにも膨大すぎる文量なので困っています。

ご助力お願いします。

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

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

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

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

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

guest

回答2

0

自己解決

ご回答を参考に、setStateで処理する関数に引数を渡さずにsetState内の処理をisChecked = !isChecked;に変更したところうまく動きました。

解決はしましたが、おそらくチェックボックスを生成するクラスのプロパティの型の明記が不十分だったのかもしれません。

class TaskCheckbox extends StatelessWidget { TaskCheckbox({this.checkboxState, this.toggleCheckboxState}); final bool? checkboxState; - final Function? toggleCheckboxState;これがおかしいかも + final Function?<bool?> toggleCheckboxState; 引数が足りなかった?

兎にも角にも解決して安心です。

ご回答いただいた方、大変ありがとうございました。

投稿2021/07/15 23:29

massanmesu

総合スコア36

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

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

0

ちょっとこれだけに難しい書き方してると思ったので、
書き方違うんですけど

dart

1bool isChecked = false; 2 3void checkboxCallback(){ 4 setState(() { 5 isChecked = !isChecked; 6 }); 7 } 8 9ListTile( 10 title: Text( 11 'This is a task', 12 style: TextStyle( 13 decoration: isChecked ? TextDecoration.lineThrough : null), 14 ), 15 // カスタムチェックボックス 16 trailing: IconButton( 17 icon: Icon( 18 isChecked 19 ?Icons.check_box_outlined 20 :Icons.check_box_outline_blank, 21 size: 20.0, 22 ), 23 onPressed: (){ 24 checkboxCallback(); 25 }, 26 ), 27 )

これでも同じ動きできますよ。

投稿2021/07/15 11:19

編集2021/07/16 03:07
endiv

総合スコア161

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

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

massanmesu

2021/07/15 23:18

setState内の処理って非同期必須なんですかね? 個人的にはbool値を変えるだけで重い処理はしていないので不要かと思っておりました。試してみます。
endiv

2021/07/16 03:06

おっしゃる通りで必要ありません。 コードを書き直しておきます。 失礼しました
massanmesu

2021/07/16 08:17

ありがとうございます。無事動きました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問