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

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

ただいまの
回答率

88.81%

Flutter(Dart)のDismissibleエラー回避方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 724

前提・実現したいこと

Flutter(Dart)を用いて簡易的なToDoアプリを作成しています。
ToDoタスクのリストの削除処理を構築している中で、下記のようなエラーが出ましたが、解決できず大変困っています。
初心者なので、ソースコードが汚いですが、どなたか力を貸していただけると助かります。。

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

削除したeidgetがまた構造の中にあるためエラー発生。

Performing hot reload...                                                
Reloaded 1 of 478 libraries in 396ms.
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building Dismissible-[<'0'>](dirty, dependencies:
flutter: [Directionality], state: _DismissibleState#74b1e(tickers: tracking 2 tickers)):
flutter: A dismissed Dismissible widget is still part of the tree.
flutter: Make sure to implement the onDismissed handler and to immediately remove the Dismissible widget from
flutter: the application once that handler has fired.
flutter:
flutter: The relevant error-causing widget was:
flutter:   Dismissible-[<'0'>]
flutter:   file:///Users/kazuma/Desktop/myproject/flutter-study/todo_app/lib/main.dart:53:20
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      _DismissibleState.build.<anonymous closure> (package:flutter/src/widgets/dismissible.dart:526:11)
flutter: #1      _DismissibleState.build (package:flutter/src/widgets/dismissible.dart:535:8)
flutter: #2      StatefulElement.build (package:flutter/src/widgets/framework.dart:4334:27)
flutter: #3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4223:15)
flutter: #4      Element.rebuild (package:flutter/src/widgets/framework.dart:3947:5)
flutter: #5      StatefulElement.update (package:flutter/src/widgets/framework.dart:4413:5)
flutter: #6      Element.updateChild (package:flutter/src/widgets/framework.dart:2977:15)
flutter: #7      SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:545(ddd78475600b5492fc67889427724d06.png)════════════════════════════════════════════════════════════════════════════════════════════════════

エラー説明

上記のToDOリストを下から順にスワイプして削除するとエラーにならないです。
test3→test2→test1

一方、下から順に削除しないとエラーになります。
test3,test2をスワイプして削除する前にtest1 を削除した時点で上記のエラー。

該当のソースコード

エラー箇所抜粋
下記の return Dismissibleでエラーが発生。

    @override
    Widget build(BuildContext context) => Scaffold(
          key: _scaffoldKey,
          appBar: AppBar(
            title: Text('Todoリスト'),
          ),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () {
              // Todo入力画面への遷移
              _navigateAndInputTodo(context);
            },
          ),
          body: ListView.builder(
            itemCount: _todos.length, //ここで表示可能なリスト数を制限しないと、表示できなくなった時にエラーになる。
            itemBuilder: (BuildContext context, int index) {
              return Dismissible( //**ここでエラー発生**
                // KeyはFlutterが要素を一意に特定できるようにするための値を設定する。
                key: Key(index.toString()),
                // onDismissedの中にスワイプされた時の動作を記述する。
                // directionにはスワイプの方向が入るため、方向によって処理を分けることができる。
                onDismissed: (direction) {
                  setState(() {
                    // スワイプされた要素をデータから削除する
                    _todos.removeAt(index);
                  });
                  // スワイプ方向がendToStart(画面左から右)の場合の処理
                  if (direction == DismissDirection.endToStart) {
                    Scaffold.of(context).removeCurrentSnackBar();
                    Scaffold.of(context)
                        .showSnackBar(SnackBar(content: Text("削除しました")));
                    // スワイプ方向がstartToEnd(画面右から左)の場合の処理
                  } else {
                    Scaffold.of(context).removeCurrentSnackBar();
                    Scaffold.of(context)
                        .showSnackBar(SnackBar(content: Text("削除しました")));
                  }
                },
                // スワイプ方向がendToStart(画面左から右)の場合のバックグラウンドの設定
                background: Container(
                  alignment: Alignment.centerLeft,
                  color: Colors.redAccent[700],
                  child: Padding(
                      padding: EdgeInsets.fromLTRB(20.0, 0.0, 0.0, 0.0),
                      child: Icon(Icons.delete_forever, color: Colors.white)),
                ),

                // スワイプ方向がstartToEnd(画面右から左)の場合のバックグラウンドの設定
                secondaryBackground: Container(color: Colors.blue),

                child: Card(
                  child: ListTile(
                      title: Text(_todos[index].title),
                      onTap: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) =>
                                  DetailScreen(todo: _todos[index])),
                        );
                      }),
                ),
              );
            },
          ),
        );

ソース全量
https://github.com/kazumaz/flutter-study/blob/master/todo_app/lib/main.dart

試したこと

下記の記事などを参考に実装しているのですが、解決には至らず。。
https://tutorialmore.com/questions-273759.htm

補足情報(FW/ツールのバージョンなど)

(base) kazumanoMacBook-Air:todo_app kazuma$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.1 19B88, locale ja-JP)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 11.3)
[✓] Android Studio (version 3.5)
[!] IntelliJ IDEA Community Edition (version 2019.2.4)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] VS Code (version 1.41.1)
[✓] Connected device (1 available)

! Doctor found issues in 1 category.
(base) kazumanoMacBook-Air:todo_app kazuma$ 

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

DismissiblekeyKey(index.toString())を指定しているのが原因だと思います。
これだと、途中のTODOが削除された場合、削除したindexが他のTODOで使いまわされてしまい、不整合が起きるので、エラーになっているようです。

DismissiblekeyObjectKey(_todos[index])にするとTODOごとにユニークなキーになるので、エラーが発生しなくなりました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/11 10:31

    popobot様
    ご回答ありがとうございます。私の方でも試したところ、無事解消されました。
    心から感謝しております。

    キャンセル

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

  • ただいまの回答率 88.81%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る