gegobyte
gegobyte

Reputation: 5565

How to add styling to selected ListTile in Flutter?

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?

Upvotes: 12

Views: 31502

Answers (3)

Riki137
Riki137

Reputation: 2561

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),
    );
  }
}

Upvotes: 20

gegobyte
gegobyte

Reputation: 5565

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.

Upvotes: 7

mr. nobodey
mr. nobodey

Reputation: 11

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

Upvotes: 1

Related Questions