Kshitij Dhakal
Kshitij Dhakal

Reputation: 844

What is the correct way to use Dismissible Widget inside CustomScrollView in flutter?

I am trying to put basic DismissibleWidget inside CustomScrollView. Here is the code

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool change = false;
  List<String> someList;

  @override
  void initState() {
    super.initState();
    someList = List.generate((20), (index) => 'Data $index');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          body: CustomScrollView(
            slivers: <Widget>[
              SliverAppBar(
                title: Text("Dismissible in Slivers"),
              ),
              SliverList(
                delegate: SliverChildBuilderDelegate(
                    (context, index) => Dismissible(
                          key: ValueKey<String>(someList[index]),
                          child: ListTile(
                            title: Text(someList[index]),
                            onTap: () {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) =>
                                      SecondPage(someList[index])));
                            },
                          ),
                          onDismissed: (dismissDirection) {
                            someList.remove(index);
                          },
                        ),
                    childCount: someList.length),
              )
            ],
          ),
        ));
  }
}

class SecondPage extends StatelessWidget {
  final String title;

  SecondPage(this.title);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(this.title),
      ),
    );
  }
}

But when ListTile is tapped and user is routed to SecondPage; and user navigates back it shows following errors.

A dismissed Dismissible widget is still part of the tree. Make sure to immediately remove the Dismissible widget from the application once that handler has fired.

Normally this would be solved by using ListView.builder when not using Slivers as follow.

ListView.builder(
itemCount: someList.length,
itemBuilder: (context, index) => Dismissible(
  key: ValueKey<String>(someList[index]),
  child: ListTile(
    title: Text(someList[index]),
    onTap: () {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (context) =>
              SecondPage(someList[index])));
    },
  ),
  onDismissed: (dissmissDirection) {
    setState(() {
      someList.removeAt(index);
    });
  },
))

But I cannot find way to get rid of this error while using CustomScrollView.

Upvotes: 1

Views: 541

Answers (1)

chunhunghan
chunhunghan

Reputation: 54367

You need to use removeAt inside setState
You can copy paste run full code below
code snippet

 onDismissed: (dismissDirection) {
                        setState(() {
                          someList.removeAt(index);
                        });

                      }

working demo

enter image description here

full code

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';

    void main() => runApp(MyApp());

    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }

    class _MyAppState extends State<MyApp> {
      bool change = false;
      List<String> someList;

      @override
      void initState() {
        super.initState();
        someList = List.generate((20), (index) => 'Data $index');
      }

      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: Scaffold(
              body: CustomScrollView(
                slivers: <Widget>[
                  SliverAppBar(
                    title: Text("Dismissible in Slivers"),
                  ),
                  SliverList(
                    delegate: SliverChildBuilderDelegate(
                            (context, index) => Dismissible(
                          key: ValueKey<String>(someList[index]),
                          child: ListTile(
                            title: Text(someList[index]),
                            onTap: () {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) =>
                                      SecondPage(someList[index])));
                            },
                          ),
                          onDismissed: (dismissDirection) {
                            setState(() {
                              someList.removeAt(index);
                            });

                          },
                        ),
                        childCount: someList.length),
                  )
                ],
              ),
            ));
      }
    }

    class SecondPage extends StatelessWidget {
      final String title;

      SecondPage(this.title);

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Text(this.title),
          ),
        );
      }
    }

Upvotes: 1

Related Questions