150

How could I add divider to list? I use Flutter for Android. I want to add a divider between each List item and I want to colorize the divider and add styles.

I tried to add new divider(); but I got errors. I also tried return new divider();.

Here is the screen shot of my app:

And here is my code:

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

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

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
          primarySwatch: Colors.purple,

          buttonTheme: const ButtonThemeData(
            textTheme: ButtonTextTheme.primary,
          )
      ),
      home: const MyHomePage(),
    );
  }
}

class Kitten {
  const Kitten({this.name, this.description, this.age, this.imageurl});

  final String name;
  final String description;
  final int age;
  final String imageurl;
}

final List<Kitten> _kittens = <Kitten>[
  Kitten(
      name: "kitchen",
      description: "mehraboon",
      age: 2,
      imageurl:
      "https://images.pexels.com/photos/104827/cat-pet-animal-domestic- 
      104827.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=350",
  ),
  Kitten(
      name: "garage",
      description: "khashen",
      age: 1,
      imageurl:
      "https://images.pexels.com/photos/4602/jumping-cute-playing-animals.jpg? 
      auto=compress&cs=tinysrgb&dpr=2&h=350",
  ),
  Kitten(
      name: "bedroom",
      description: "khar zoor",
      age: 5,
      imageurl:
      "https://images.pexels.com/photos/978555/pexels-photo-978555.jpeg? 
      auto=compress&cs=tinysrgb&dpr=2&h=350",
  ),
  Kitten(
      name: "living room",
      description: "chorto",
      age: 3,
      imageurl:
      "https://images.pexels.com/photos/209037/pexels-photo-209037.jpeg? 
      auto=compress&cs=tinysrgb&dpr=2&h=350",
  ),
];

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key key}) : super(key: key);

  Widget _dialogBuilder(BuildContext context, Kitten kitten) {
    return SimpleDialog(contentPadding: EdgeInsets.zero, children: [
      Image.network(kitten.imageurl, fit: BoxFit.fill),
      Padding(
          padding: const EdgeInsets.all(16.0),
          child:
          Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
            Text(kitten.name),
            Text('${kitten.age}'),
            SizedBox(
              height: 16.0,
            ),
            Text(kitten.description),
            Align(
              alignment: Alignment.centerRight,
              child: Wrap(
                children: [
                  FlatButton(onPressed: () {}, child: const
                  Text("noooo!"),color: Colors.red,),
                  Padding(padding: const EdgeInsets.all(2.0),),
                  RaisedButton(onPressed: () {}, child: const
                  Text("yesss!"),color: Colors.green)
                ],
              ),
            )
          ]))
    ]);
  }

  Widget _listItemBuilder(BuildContext context, int index) {
    return new GestureDetector(

      onTap: () => showDialog(
          context: context,
          builder: (context) => _dialogBuilder(context, _kittens[index])),
      child:
      Container(

        padding: EdgeInsets.all( 16.0),
        alignment: Alignment.centerLeft,
        child: Text(_kittens[index].name,
            style: Theme.of(context).textTheme.headline),

      ),


    ) ;

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Keys"),
        centerTitle: true,


      ),
      body: ListView.builder(
        itemCount: _kittens.length,
        itemExtent: 60.0,
        itemBuilder: _listItemBuilder,

      ),
    );
  }
}
 
Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
Amin Joharinia
  • 1,643
  • 2
  • 9
  • 9

11 Answers11

339

There are a number of ways to do the same thing. Let me compare them here.

For a short static list

Use ListTile.divideTiles

ListView(
  children: ListTile.divideTiles( //          <-- ListTile.divideTiles
      context: context,
      tiles: [
        ListTile(
          title: Text('Horse'),
        ),
        ListTile(
          title: Text('Cow'),
        ),
        ListTile(
          title: Text('Camel'),
        ),
        ListTile(
          title: Text('Sheep'),
        ),
        ListTile(
          title: Text('Goat'),
        ),
      ]
  ).toList(),
)

For a long dynamic list

Use ListView.separated.

ListView.separated(
  itemCount: 100,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('$index sheep'),
    );
  },
  separatorBuilder: (context, index) {
    return Divider();
  },
)

This returns two widgets for every item, except for the last item. The separatorBuilder is used to add the divider.

For adding a divider after the last item

Create a custom item widget that uses a Divider or BoxDecoration.

Using Divider

final items = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];

@override
Widget build(BuildContext context) {
  return ListView.builder(
    itemCount: items.length,
    itemBuilder: (context, index) {
      return Column(
        children: <Widget>[
          ListTile(
            title: Text(items[index]),
          ),
          Divider(), //                           <-- Divider
        ],
      );
    },
  );
}

Using BoxDecoration

final items = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];

@override
Widget build(BuildContext context) {
  return ListView.builder(
    itemCount: items.length,
    itemBuilder: (context, index) {
      return Container(
        decoration: BoxDecoration( //                    <-- BoxDecoration
          border: Border(bottom: BorderSide()),
        ),
        child: ListTile(
          title: Text(items[index]),
        ),
      );
    },
  );
}

Both Divider and BoxDecoration are customizable as far as the line height and color go. Divider also has an indent option, but you could get a BoxDecoration to do the same thing with some padding.

For more style

Use a Card

final items = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];

@override
Widget build(BuildContext context) {
  return ListView.builder(
    itemCount: items.length,
    itemBuilder: (context, index) {
      return Card( //                           <-- Card
        child: ListTile(
          title: Text(items[index]),
        ),
      );
    },
  );
}
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
109

The most correct way is to use ListView.separated

ListView.separated(
     itemCount: 25,
     separatorBuilder: (BuildContext context, int index) => Divider(height: 1),
     itemBuilder: (BuildContext context, int index) {
       return ListTile(
         title: Text('item $index'),
       );
     },
);
Jossef Harush Kadouri
  • 32,361
  • 10
  • 130
  • 129
Danylo
  • 5,152
  • 2
  • 17
  • 13
  • Also, note using ListView.separated last Item won't have the divider you can show it like this ```if (index == itemCount - 1) { return Divider(height: 1); }``` – Mahesh Jamdade Apr 20 '21 at 03:34
25

Put your widget inside container with BoxDecoration as

Container(
   child: YourWidgetHere(),
   decoration: BoxDecoration(
      border: Border(bottom: BorderSide(color: Colors.black26))),
);
Dhiraj Sharma
  • 4,364
  • 24
  • 25
  • This enables using Column instead of ListView. Which is useful if you don't want the scrollbar included in ListView. – Alex May 24 '21 at 12:57
18

recently I use this code to set divider:

ListView.separated(
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text("Hello", style: TextStyle(
              color: Theme
                  .of(context)
                  .primaryColor
          ),),

        );
      },
      separatorBuilder: (context, index) =>Divider(height: 1, color: Colors.green),
      itemCount: 30),

and it works.

For example, I have added my app's screenshot

enter image description here

Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
15

On the flutter getting started tutorial it is covered, the solution they provide is something like this:

  body: ListView.builder(
    itemCount: _kittens.length,
    itemExtent: 60.0,
    itemBuilder: (context, i) {
        // Add a one-pixel-high divider widget before each row in theListView.
        if (i.isOdd) return new Divider(color: Colors.purple); // notice color is added to style divider

        return _listItemBuilder();
      },
  ),
  ...

That should add the dividers taking into account the odd and even rows to do so.

Also to color the divider pas "color" to the Divider Class:

new Divider(color: Colors.purple);
Lucas
  • 9,871
  • 5
  • 42
  • 52
  • 12
    If the itemCount is `_kittens.length` and every other item you are returning a Devider, aren't you going to miss half of the kittens? The getting started tutorial is different than your example. – Suragch Jan 26 '19 at 23:09
  • The divider is added once for every two otherwise you get two dividers with no kitten between them. The tutorial does cover it as shown in my answer, however they add more to it but it is not needed for it to work. when I tested it, this worked perfectly. – Lucas Jan 26 '19 at 23:56
  • For this to work you'll need `itemCount: _kittens.length * 2` otherwise yeah you're missing second half of the kittens. – sleighty Sep 15 '21 at 21:28
7

Check out this issue: ListView.builder should let clients specify a divider It makes clear that:

  1. if you need to build your list with dynamic elements, for now you'll have to deal with this issue on your own. I'd recommend in the row widget building, you include a List Divider at the bottom with a column or something, except for the last one (you can test for index == listData.length - 1).

  2. But if, like in the example you show, you already know all the lists data before hand, or you build it without a ListView.builder, then you can and should use the named constructor ListView.divideTiles

dsilveira
  • 366
  • 2
  • 12
5

following this Just add Divider() :

         Column(
                children: <Widget>[
                  Container(
                    padding: EdgeInsets.all(16.0),
                    child: Column(
                      children: <Widget>[
                        Image.network(video["imageUrl"]),
                        Container(
                          height: 6.0,
                        ),
                        Text(
                          video["name"],
                          textScaleFactor: 1.05,
                          style: TextStyle(fontWeight: FontWeight.bold),
                        ),
                      ],
                    ),
                  ),
                  Divider(
                    color: Theme.of(context).primaryColor,
                  )
                ],
              );                                                                           
Dharmesh Mansata
  • 4,422
  • 1
  • 27
  • 33
3

Dart 2.3

Another way, especially for generic non-list-view: Using for in a Collection (link) with the ... spread operator

Column(
   children: [
     for(var i=0; i<4; i+=1)
     ...[Container(height: 100, width: 100),
         Divider()
      ]])
Roddy R
  • 1,222
  • 10
  • 10
2

The question assumes that we have access to material.dart for Android styling (ListTile and Divider). If you want Cupertino styles, we can:

  1. Use a Column view wrapper for the row, and add a Container with height 1.

     Column(
       children: <Widget>[
         row, // A custom Row
         Padding(
           padding: const EdgeInsets.only(
             left: 16,  // Adjust separator left padding.
             right: 16, // Adjust separator right padding.
           ),
           child: Container(
             height: 1,
             color: Styles.productRowDivider, // Custom style
           ),
         ),
       ],
     );
    
  2. The Divider is not available in cupertino.dart. We can use the same Container technique with ListView.separated:

     ListView.separated(
       itemCount: 100,
       itemBuilder: (context, index) {
         return row;
       },
       separatorBuilder: (context, index) {
         return Container(
                 height: 1,
                 color: Styles.productRowDivider, // Custom style
               );
       },
     );
    
Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
  • One can import both `material.dart` and `cupertino.dart`, and use the former just for `Divider`. This is no overhead because the tree shaking will ensure that only what is used will be included in the release. – Alexey Inkin Dec 19 '21 at 07:13
  • Yes. To clarify, I meant that we need `cupertino.dart` for Cupertino styling. – Pranav Kasetti Dec 20 '21 at 17:33
1

Thats another way usig Container.

 ListTile(
        leading: Icon(Icons.home),
        title: Text('Home'),
 ),
 Container(height: 1, color: Colors.grey), //divider
 ListTile(
        leading: Icon(Icons.logout),
        title: Text('Logout'),
 ),
Márcio Rossato
  • 971
  • 1
  • 11
  • 20
-2

Create a Container like this

Container(height: 1, color: Colors.grey),

And add with your ListTile like this

 ListView.builder(
  itemCount: _feed.items.length,
  itemBuilder: (BuildContext context, int index) {
    final item = _feed.items[index];

     return  Column(
         children: <Widget>[
      Container(height: 1, color: Colors.grey),  //Container for devider
      ListTile(                                  //Your tile item
      title: title(item.title),
      subtitle: subtitle(item.pubDate),
      leading: thumbnail(item.enclosure.url),
      trailing: rightIcon(),
      contentPadding: EdgeInsets.all(5.0),
      onTap: () => openFeed(item.link),
    )]);
  },
);

Now you can see final output in my screenshot

enter image description here [1]: https://i.stack.imgur.com/EZuIg.jpg

  • If you are going to use `ListView.builder`, you might as well replace it with `ListView.separated`. That way, you can pass a new `IndexedWidgetBuilder` on `separatorBuilder` and build your divider there. – Arthur Bertemes Dec 26 '21 at 14:57