Dismissible Expanded List

A Flutter package to provide an ability to display hierarchical data in the form of list as well as allows to swipe the individual tiles.

Getting Started

Dismissible Expanded List is written in dart. It provides us an ability to display hierarchical data in the form of list as well as allowing us to swipe the individual tiles. Tapping a tile expands or collapses the view of its children. When a tile is collapsed its children are disposed so that the widget footprint of the list only reflects what’s visible.

User can enable/disable swipe functionality for parent or child items by providing simple configurations. A complete list of configurable params is mentioned below.

Demo

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

dependencies:
  dismissible_expanded_list: ^0.2.x

2. Install it

You can install packages from the command line:

with Flutter

$ flutter packages get

Alternatively, your editor might support flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:dismissible_expanded_list/dismissible_expanded_list.dart';

How to use

Using Dismissible Expanded List is quite easy, all you need to do is

return ListView.builder(
    itemBuilder: (BuildContext context, int index) =>
        DismissibleExpandableList(
      parentIndex: index,
      entry: list[index],
      config: config,
      onItemClick: (parentIndex, childIndex, ExpandableListItem item) {
        print('onItemClick called');
        onItemClick(parentIndex, childIndex);
      },
      onItemDismissed:
          (parentIndex, childIndex, direction, removeTileOnDismiss, item) {
        if (direction == DismissDirection.endToStart) {
          onItemDismissed(parentIndex, childIndex, removeTileOnDismiss);
        } else {
          onItemDismissed(parentIndex, childIndex, removeTileOnDismiss);
        }
      },
    ),
    itemCount: mockData.length,
  );

How to Configure

/// Configuration example
DismissibleListConfig config = DismissibleListConfig()
  ..badgeWidth = 80.0
  ..listElevation = 3.0
  ..infoBadgeElevation = 0.0
  ..infoIconSize = 15.0
  ..removeTileOnDismiss = false
  ..allowBatchSwipe = true
  ..allowChildSwipe = true
  ..allowParentSelection = true
  ..showBorder = false
  ..showInfoBadge = true
  ..titleStyle = TextStyles.title
  ..titleSelectedStyle = TextStyles.titleSelected
  ..subTitleStyle = TextStyles.subTitle
  ..subTitleSelectedStyle = TextStyles.subTitleSelected
  ..trailingIcon = Icons.info_outline
  ..lineColor = Colors.grey[400]
  ..selectionColor = Color(0xFFcee9f0)
  ..rightSwipeColor = Colors.green
  ..leftSwipeColor = Colors.red
  ..iconColor = Colors.black87
  ..iconSelectedColor = Colors.black87
  ..backgroundColor = Colors.white;

List of params

PropertyTypeDefault ValueDescription
badgeWidthdouble80.0The (optional) param to control badge width displayed at the top right.
infoBadgeElevationdouble0.0The (optional) param to control the card elevation for info badge displayed at the top right.
listElevationdouble3.0The (optional) param to control the card elevation for dismissible list item.
infoIconSizedouble15.0The (optional) param to control the size of info icon displayed in-front of the title.
removeTileOnDismissbooltrueThe (optional) param to control either to remove dismissible list items from list or to keep them. If true item will be remove from the list and the rest of the items will adjust accordingly, else item will stay at its place and a callback with swiped item will be returned.
allowBatchSwipebooltrueThe (optional) param to control parent/batch swipe at once. If true parent/batch will be swiped and removed from list, else it wont and will act as a normal list item.
allowChildSwipebooltrueThe (optional) param to control child swipe. If true user will be able to swipe the child else it won't and will act as a normal list item.
allowParentSelectionbooltrueThe (optional) param to control parent selection. If true by selecting a child parent will also be selected else only child will show as selected.
showBorderboolfalseThe (optional) param to add an extra border between expanded and other list items when one of the list item is expanded. If true an extra border will be added to top and bottom of expanded item to distinguish it from other items else there will be no boarder.
showInfoBadgebooltrueThe (optional) param to control either to show info badge or not. if true info badge will be displayed at the top right corner of the dismissible list item.
titleStyleTextStyleTextStyles.titleThe (optional) param to set font style of the title.
titleSelectedStyleTextStyleTextStyles.titleSelectedThe (optional) param to set selected font style of the title.
subTitleStyleTextStyleTextStyles.subTitleThe (optional) param to set font style of the sub-title.
subTitleSelectedStyleTextStyleTextStyles.subTitleSelectedThe (optional) param to set selected font style of the sub-title.
trailingIconIconDataIcons.info_outlineThe (optional) param to set the trailing icon.
topLeftIconIconDataIcons.info_outlineThe (optional) param to set the icon at the top left corner of the list tile.
bottomLeftIconIconDataIcons.info_outlineThe (optional) param to set the icon at the bottom left corner of the list tile.
bottomRightIconIconDataIcons.info_outlineThe (optional) param to set the icon at the bottom right corner of the list tile.
lineColorColorColors.grey400The (optional) param to set the line color of the expanded list item.
selectionColorColorColor(0xFFcee9f0)The (optional) param to set the list item selection color.
rightSwipeColorColorColors.greenThe (optional) param to set the swipe color of the list item when swiped from left to right.
leftSwipeColorColorColors.redThe (optional) param to set the swipe color of the list item when swiped from right to left.
iconColorColorColors.black87The (optional) param to set the trailing icon color.
iconSelectedColorColorColors.black87The (optional) param to set the trailing icon color when list item is selected.
backgroundColorColorColors.whiteThe (optional) param to set the background color of list item.
cornerBackgroundColorColorColor(0xFFf3f3f3)The (optional) param to set the background color of corners.
cornerSelectionColorColorColor(0xFFf3f3f3)The (optional) param to set the selection color of corners.
parentIndexintnullThe (required) param to populate list item data.
entryExpandableListItemnullThe (required) param to populate list item data.
configDismissibleListConfignullThe (required) param to set the dismissible list item configuration. e.g. background color, trailing icon size etc.
onItemClickOnItemClicknullThe (optional) param to get the call back whenever list item will be tapped.
onItemDismissedOnItemDismissednullThe (optional) param to get the call back whenever list item will be swiped.
iconsListnullThe (optional) param to show info icons under subtitle

Complete Example

import 'package:dismissible_expanded_list/constants/text_styles.dart';
import 'package:dismissible_expanded_list/widgets/dismissible_expanded_list_widget.dart';
import 'package:dismissible_expanded_list/model/entry.dart';
import 'package:example/mock.dart';
import 'package:flutter/material.dart';
import 'package:dismissible_expanded_list/model/dismissible_list_configuration.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: ExpansionTileSample(),
    );
  }
}

class ExpansionTileSample extends StatefulWidget {
  @override
  _ExpansionTileSampleState createState() => _ExpansionTileSampleState();
}

class _ExpansionTileSampleState extends State<ExpansionTileSample> {
  String title = 'Not Yet Selected';
  String selectedId = '1';
  bool removeTileOnDismiss = true;

  final List<ExpandableListItem> list = mockData;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Color(0xFF2e6f85),
          title: const Text('ExpansionTile'),
        ),
        body: Material(
          child: MediaQuery.of(context).orientation == Orientation.landscape
              ? Row(
                  children: <Widget>[_buildLeftSide(), _buildRightSide()],
                )
              : Row(
                  children: <Widget>[_buildRightSide()],
                ),
        ),
      ),
    );
  }

  Widget _buildRightSide() {
    /// Configuration example
    DismissibleListConfig config = DismissibleListConfig()
      ..badgeWidth = 80.0
      ..listElevation = 3.0
      ..infoBadgeElevation = 0.0
      ..infoIconSize = 15.0
      ..removeTileOnDismiss = false
      ..allowBatchSwipe = true
      ..allowChildSwipe = true
      ..allowParentSelection = true
      ..showBorder = false
      ..showInfoBadge = true
      ..titleStyle = TextStyles.title
      ..titleSelectedStyle = TextStyles.titleSelected
      ..subTitleStyle = TextStyles.subTitle
      ..subTitleSelectedStyle = TextStyles.subTitleSelected
      ..trailingIcon = Icons.info_outline
      ..lineColor = Colors.grey[400]
      ..selectionColor = Color(0xFFcee9f0)
      ..rightSwipeColor = Colors.green
      ..leftSwipeColor = Colors.red
      ..iconColor = Colors.black87
      ..iconSelectedColor = Colors.black87
      ..backgroundColor = Colors.white;

    return Expanded(
      flex: 1,
      child: ListView.builder(
        itemBuilder: (BuildContext context, int index) =>
            DismissibleExpandableList(
          parentIndex: index,
          entry: list[index],
          config: config,
          onItemClick: (parentIndex, childIndex, ExpandableListItem item) {
            print('onItemClick called');
            onItemClick(parentIndex, childIndex);
          },
          onItemDismissed:
              (parentIndex, childIndex, direction, removeTileOnDismiss, item) {
            if (direction == DismissDirection.endToStart) {
              onItemDismissed(parentIndex, childIndex, removeTileOnDismiss);
            } else {
              onItemDismissed(parentIndex, childIndex, removeTileOnDismiss);
            }
          },
        ),
        itemCount: mockData.length,
      ),
    );
  }

  Widget _buildLeftSide() {
    return Expanded(
      flex: 2,
      child: Container(
        margin: EdgeInsets.only(left: 5.0, top: 5.0, bottom: 5.0, right: 2.0),
        height: double.infinity,
        decoration: BoxDecoration(
            color: Colors.white, borderRadius: BorderRadius.circular(10.0)),
        child: Text(title),
      ),
    );
  }

  // general methods:-----------------------------------------------------------
  void onItemClick(int parentIndex, int childIndex) {
    setState(
      () {
        if (childIndex == -1) {
          title = mockData[parentIndex].title;
          selectedId = mockData[parentIndex].id;

          // setting entry to true
          mockData.forEach((item) => item.reset());
          mockData[parentIndex].selected = true;
        } else {
          selectedId = mockData[parentIndex].children[childIndex].id;
          title = mockData[parentIndex].children[childIndex].title;

          // setting entry to true
          mockData.forEach((item) => item.reset());
          mockData[parentIndex].selected = true;
          mockData[parentIndex].children[childIndex].selected = true;
        }
      },
    );
  }

  void onItemDismissed(
      int parentIndex, int childIndex, bool removeTileOnDismiss) {
    setState(
      () {
        // check to see if user wants to remove swiped items from list
        // if yes then remove item from list
        // else show user a message about swiped item
        if (removeTileOnDismiss) {
          if (childIndex == -1) {
            mockData.removeAt(parentIndex);
          } else {
            // check to see if its the last child
            // if yes, then remove parent as well
            // else, only remove child
            if (mockData[parentIndex].children != null &&
                mockData[parentIndex].children.length > 1) {
              mockData[parentIndex].children.removeAt(childIndex);
            } else {
              mockData.removeAt(parentIndex);
            }
          }
        } else {
          // show user a message that item has been swiped
        }
      },
    );
  }
}

Libraries

custom_expansion_tile
dismissible_expanded_list
dismissible_expanded_list
dismissible_list_configuration
entry
rectangular_clipper
text_styles
timeline_painter