Swipe to Delete Widget in Flutter – Dismissible Widget

Swipe to Delete Widget in Flutter – Dismissible Widget

Dismissible Widget helps in creating a Swipe to Delete Motion which is a very important UI action in any application. Creating the same effect in Android is discussed in Detail in the article on Swipe to Delete in Android. In this article, we will look at a much simpler and easier way to perform this Action in Flutter.

To begin with, the article makes use of some of the following concepts, Scaffold in Flutter & Stateless and Stateful Widgets in Flutter.

Make sure to give those two a read before jumping into this article. Let us start the application with a simple Template to help us in understanding all the attributes in depth.

We will be making use of the Widget called the Dismissible Widget. This widget is capable of handling all the important actions including swiping and removing it from the stack tree seamlessly. It reduces the lines of code by a huge margin and gives a cleaner look to the Application.

Dismissible Widget – Understanding the basics

Dismissible Widget is created using the class Dismissible and contains a lot of attributes to change the properties of this action. Since, there can be a lot of factors that can determine the swipe to delete including direction, duration, size. All of these are handled easily using this Widget.

Sample Constructor looks like – 

Dismissible({@required Key key@required Widget childWidget backgroundWidget secondaryBackgroundConfirmDismissCallback confirmDismissVoidCallback onResizeDismissDirectionCallback onDismissedDismissDirection directionDismissDirection.horizontalDuration resizeDurationconst Duration(milliseconds: 300)Map<DismissDirectiondouble> dismissThresholdsconst <dismissdirection, double=””>{}</dismissdirection,>Duration movementDurationconst Duration(milliseconds: 200)double crossAxisEndOffset0.0DragStartBehavior dragStartBehaviorDragStartBehavior.start })

We will additionally create a simple template to help us in creating the dismissible widget in depth.

import 'dart:async';

import 'package:flutter/material.dart';

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

class DismissibleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample Dismissible Widget',
      home: DismissibleWidget(),
    );
  }
}

class DismissibleWidget extends StatefulWidget {
  DismissibleWidget({Key key}) : super(key: key);

  @override
  _DismissibleWidgetState createState() => _DismissibleWidgetState();
}

class _DismissibleWidgetState extends State<DismissibleWidget> {


  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold();
}
}

Like you can see, the Scaffold and the Stateful Widget is used as its parent to create a Base App for us to work with.

We will look at all the properties that the Dismissible Widget class has and look at how they are used in the widget specifically.

Dismissible – Important Attributes

Key

Key is the most important attribute of the Dismissible Widget. It is important that every Dismissible Widget in the lifecycle of the Application has a unique key. It is important to understand about keys in Dismissible widget because it defines how the Widget is removed in the background. All the dismissible widgets are removed when swipe by simply removing the key from the Stack tree and rebuilding it.

So it is important to give a unique key for every Dismissible Widget and making sure that the Key() constructor is used while doing so. In the below example program in the following section, it is present to provide better context.

child

The child is the most important attribute of this widget. It lets any Widget be a part of it. Could be a Text, Image or a Card and many more. Anything that is under the child attribute is given the property of swiping and deleting.

The key which is going to be removed while doing so completely removes this Widget also and the action of swiping and deleting is performed. In the final example below, the Card Widget is used as the child while the code block below uses the Text Widget for better understanding.

Dismissible(
  key: Key("First Card"),
  child: Text("Sample First Card"))

Simple use of this will create the below App

Dismissible Widget Child attribute
Dismissible Widget Child attribute
background

Background attribute is another important attribute that comes under the Dimissble widget. It lets you put any widget behind the child widget to make sure that as soon as the child widget deletes from the screen space, the widget present in the background attribute is shown before going away.

This is useful to give a confirmation that the widget/card has been removed from the UI. You can make use of the attribute like given below,

Dismissible(
key: Key("First Card"),
child: Text("Sample First Card"),
background: Text("First Card is deleted"),)
secondaryBackground

SecondaryBackground is another attribute that helps you decide what should come in between the child and the background attribute.

This creates a cleaner UI experience for the end user. The attribute can be created like given below,

Dismissible(
key: Key("First Card"),
child: Text("Sample First Card"),
background: Text("First Card is deleted"),
  secondaryBackground: Text("In between First card and background"),
)
direction

Direction attribute lets you choose which direction the Widget has to be swiped for deletion. Could be vertical or horizontal and it is decided using this attribute. To create the direction, make use of the DismissibleDirection class and call the respective direction. Could be up, down, horizontal, vertical etc.

To understand better, follow the below code,

Dismissible(
key: Key("First Card"),
child: Text("Sample First Card"),
background: Text("First Card is deleted"),
secondaryBackground: Text("In between First card and background"),
direction: DismissDirection.up,
)
onDismissed

The important callback which gets fired when the Widget is actually dismissed. The onDismissed fires with a lot of important properties including the key and direction in which it was dismissed in and etc.

onDismissed can be used to perform confirmation actions on the Application. To better understand how the onDismissed is used, see the below code snippet.

Dismissible(
key: Key("First Card"),
child: Text("Sample First Card"),
background: Text("First Card is deleted"),
secondaryBackground: Text("In between First card and background"),
direction: DismissDirection.up,
onDismissed: (card_name){
print(card_name);
},
)

Dismissible – Final Application

I took some time to create the final application like below. Take a look at the code and the final app also following the code.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

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

class DismissibleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample Dismissible Widget',
      home: DismissibleWidget(),
    );
  }
}

class DismissibleWidget extends StatefulWidget {
  DismissibleWidget({Key key}) : super(key: key);

  @override
  _DismissibleWidgetState createState() => _DismissibleWidgetState();
}

class _DismissibleWidgetState extends State<DismissibleWidget> {
  VideoPlayerController _controller;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
    );

    // Initielize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();

    // Use the controller to loop the video.
    _controller.setLooping(true);
    super.initState();
  }

  @override
  void dispose() {
    // Ensure disposing of the VideoPlayerController to free up resources.
    _controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: Drawer(),
      backgroundColor: Color(0XFFf2f6f5),
      appBar: AppBar(
        title: Text('Sample Dismissible Example'),
        backgroundColor: Colors.black87,
      ),
      // Use a FutureBuilder to display a loading spinner while waiting for the
      // VideoPlayerController to finish initializing.
      body: Column(
        children: <Widget>[
          Dismissible(
            background: Text("First Card is dismissed"),
            secondaryBackground: Text("First Card is Going to be dismissed"),
              key: Key("First Card"),
              child: Center(
                child: Card(
                  color: Color(0XFFff7a8a),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      const ListTile(
                        leading: Icon(Icons.gamepad),
                        title: Text('Gamer Physcology'),
                        subtitle: Text('Creating a Master Class for Gamers!'),
                      ),
                      ButtonTheme.bar( // make buttons use the appropriate styles for cards
                        child: ButtonBar(
                          children: <Widget>[
                            FlatButton(
                              child: const Text('Choose Course'),
                              onPressed: () {},
                            ),
                            FlatButton(
                              child: const Text('Learn',),
                              onPressed: () {},
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ),
          ),
          Dismissible(
              key: Key("Second Card"),
              child: Center(
                child: Card(
                  color: Color(0XFFfcf594),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      const ListTile(
                        leading: Icon(Icons.satellite),
                        title: Text('Telecommunication Crash Course'),
                        subtitle: Text('Masterclass on Creating Telecommunication Videos'),
                      ),
                      ButtonTheme.bar( // make buttons use the appropriate styles for cards
                        child: ButtonBar(
                          children: <Widget>[
                            FlatButton(
                              child: const Text('Choose Course'),
                              onPressed: () { /* ... */ },
                            ),
                            FlatButton(
                              child: const Text('Learn'),
                              onPressed: () { /* ... */ },
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              )),
          Dismissible(
              key: Key("Third Card"),
              child: Center(
                child: Card(
                  color: Color(0XFFff7a8a),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      const ListTile(
                        leading: Icon(Icons.youtube_searched_for),
                        title: Text('Youtube Crash Course'),
                        subtitle: Text('Masterclass on Creating Youtube Videos'),
                      ),
                      ButtonTheme.bar( // make buttons use the appropriate styles for cards
                        child: ButtonBar(
                          children: <Widget>[
                            FlatButton(
                              child: const Text('Choose Course'),
                              onPressed: () { /* ... */ },
                            ),
                            FlatButton(
                              child: const Text('Learn'),
                              onPressed: () { /* ... */ },
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              )),
        ],
      ));
  }
}

This creates the application which looks like,

Dismissible Widget
Dismissible Widget
Dismissible Widget
Dismissible Widget

Conclusion

Swipe to Delete Action is pretty useful for a lot of apps. Now it is really easy to do so in Flutter. Let me know what works and what doesn’t in the comment section below.

“Learn and Be Curious”

Leave a Comment

Your email address will not be published. Required fields are marked *