How to add styling to selected ListTile in Flutter?

Viewed 12295

I have multiple List Tiles and I want to add a few styles to the one which is selected. To set the color of the selected tile, I have used ListTileTheme so whichever tile gets selected will get the color defined in ListTileTheme.

ListTileTheme(
  selectedTileColor: Colors.white,
  child: ...
),

I also want to set border radius on top left and bottom left of ListTile, for this purpose I am using ClipRRect

ClipRRect(
  borderRadius: BorderRadius.only(
    topLeft: Radius.circular(32),
    bottomLeft: Radius.circular(32),
  ),
  child: ListTile(
    leading: Icon(Icons.people),
    title: Text('Teams'),
    onTap: () {},
    selected: true,
  ),
),

This works well as can be seen in the image below:

enter image description here

but I had to manually add it to a particular list tile. Unlike selected tile color which was defined once and it got applied automatically on any tile where the selected property is true, how to set ClipRRect too in similar fashion so that whichever tile gets selected receives border radius on top left and bottom left?

3 Answers

You have probably done the same mistake as i did and did not study all properties of ListTile. ListTile has several useful properties like shape or selectedTileColor that can solve your problems.

import 'package:flutter/material.dart';

class SideMenuItem extends StatelessWidget {
  final String title;
  final IconData icon;
  final GestureTapCallback onTap;
  final bool active;

  const SideMenuItem({required this.title, required this.icon, required this.onTap, required this.active, Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    var borderRadius = const BorderRadius.only(topRight: Radius.circular(32), bottomRight: Radius.circular(32));
    return ListTile(
      shape: RoundedRectangleBorder(borderRadius: borderRadius),
      selectedTileColor: Colors.orange[100],
      selected: active,
      onTap: () {},
      leading: Icon(icon),
      title: Text(title),
    );
  }
}

To add styling to selected List Tile, I used ListView.builder, added all the menu items to display in list tile in a Map.

final List<Map<String, dynamic>> _menuItem = [
    {
      "title": "Home",
      "icon": Icon(Icons.home),
      "selected": false,
    },
    {
      "title": "Teams",
      "icon": Icon(Icons.people),
      "selected": true,
    },
    {
      "title": "Ideas",
      "icon": Icon(Icons.lightbulb),
      "selected": false,
    }
];

and then using ListView.builder to loop through them.

ListView.builder(
  itemCount: _menuItem.length,
  itemBuilder: (context, index) {
    return ClipRRect(
      borderRadius: BorderRadius.only(
        topLeft: Radius.circular(32),
        bottomLeft: Radius.circular(32),
      ),
      child: ListTile(
        leading: _menuItem[index]['icon'],
        title: Text(_menuItem[index]['title']),
        selected: _menuItem[index]['selected'],
        onTap: () {
          if (!_menuItem[index]['selected'])
            changeSelectedMenu(index);
          },
      ),
    );
 },
)

changeSelectedMenu function ensures that the clicked menu item gets the selected property set to true. As posted in question, selected tile color is set to true and whichever tile is white gets the rounded radius from ClipRRect.

you can use this code:

class MyListTile extends StatefulWidget {
  @override
_MyListTileState createState() => _MyListTileState();
}
class _MyListTileState extends State<MyListTile> {
 int index ;
 @override
 Widget build(BuildContext context) {
return Scaffold(
  backgroundColor: Colors.cyanAccent,
  body: ListView(
    children: [
      ClipRRect(
        borderRadius: index != null && index == 0?BorderRadius.only(
          topLeft: Radius.circular(32),
          bottomLeft: Radius.circular(32),
        ):BorderRadius.only(
          topLeft: Radius.circular(0),
          bottomLeft: Radius.circular(0),
        ),
        child:Container(
          color: index != null && index == 0?Colors.white:null,
          child: ListTile(
            focusColor: Colors.white,
            leading: Icon(Icons.people),
            title: Text('Teams'),
            onTap: () {
              setState(() {
                index = 0;
              });
            },
            selected: index != null && index == 0?true:false,
          ),
        ),
      ),
      ClipRRect(
          borderRadius: index != null && index == 1?BorderRadius.only(
            topLeft: Radius.circular(32),
            bottomLeft: Radius.circular(32),
          ):BorderRadius.only(
            topLeft: Radius.circular(0),
            bottomLeft: Radius.circular(0),
          ),
          child:Container(
            color: index != null && index == 1?Colors.white:null,
            child: ListTile(
              leading: Icon(Icons.people),
              title: Text('Teams'),
              onTap: () {
                setState(() {
                  index = 1;
                });
              },
              selected: index != null && index == 1,
            ),
          ),
      ),
      ClipRRect(
          borderRadius: index != null && index == 2?BorderRadius.only(
            topLeft: Radius.circular(32),
            bottomLeft: Radius.circular(32),
          ):BorderRadius.only(
            topLeft: Radius.circular(0),
            bottomLeft: Radius.circular(0),
          ),
          child:Container(
            color: index != null && index == 2?Colors.white:null,
            child: ListTile(
              leading: Icon(Icons.people),
              title: Text('Teams'),
              onTap: () {
                setState(() {
                  index = 2;
                });
              },
              selected: index != null && index == 2,
            ),
          ),
      ),
      ClipRRect(
          borderRadius: index != null && index == 3?BorderRadius.only(
            topLeft: Radius.circular(32),
            bottomLeft: Radius.circular(32),
          ):BorderRadius.only(
            topLeft: Radius.circular(0),
            bottomLeft: Radius.circular(0),
          ),
          child:Container(
            color: index != null && index == 3?Colors.white:null,
            child: ListTile(
              leading: Icon(Icons.people),
              title: Text('Teams'),
              onTap: () {
                setState(() {
                  index = 3;
                });
              },
                 selected: index != null && index == 3,
               ),
             ),
         ),
       ],
     ),
   );
 }

}

hope its help! but that's not good solution .you should use builder

Related