简体   繁体   中英

Change background color of ListTile upon selection in Flutter

I've made a ListView in Flutter, but now I have some ListTiles in this ListView that can be selected. Upon selection, I want the background color to change to a color of my choice. I don't know how to do that. In the docs they mention that a ListTile has a property style . However, when I try to add that (as in third last line in the code below), this style property gets a squiggly red line underneath and the compiler tells me that The named parameter 'style' isn't defined .

Widget _buildRow(String string){
  return new ListTile(
    title: new Text(string),
    onTap: () => setState(() => toggleSelection(string)),
    selected: selectedFriends.contains(string),
    style: new ListTileTheme(selectedColor: Colors.white,),
  );
}

Screenshot:

在此处输入图像描述


Short answer:

ListTile(
  tileColor: isSelected ? Colors.blue : null, 
)

Full Code:

// You can also use `Map` but for the sake of simplicity I'm using two separate `List`.
final List<int> _list = List.generate(20, (i) => i);
final List<bool> _selected = List.generate(20, (i) => false); // Fill it with false initially
  
Widget build(BuildContext context) {
  return Scaffold(
    body: ListView.builder(
      itemBuilder: (_, i) {
        return ListTile(
          tileColor: _selected[i] ? Colors.blue : null, // If current item is selected show blue color
          title: Text('Item ${_list[i]}'),
          onTap: () => setState(() => _selected[i] = !_selected[i]), // Reverse bool value
        );
      },
    ),
  );
}

I was able to change the background color of the ListTile using a BoxDecoration inside Container :

ListView (
    children: <Widget>[
        new Container (
            decoration: new BoxDecoration (
                color: Colors.red
            ),
            child: new ListTile (
                leading: const Icon(Icons.euro_symbol),
                title: Text('250,00')
            )
        )
    ]
)

If you also need an onTap listener with a ripple effect, you can use Ink :

ListView(
  children: [
    Ink(
      color: Colors.lightGreen,
      child: ListTile(
        title: Text('With lightGreen background'),
        onTap() { },
      ),
    ),
  ],
);

连锁反应

It's not ListTile that has the style property. But ListTileTheme . ListTileTheme is an inheritedWidget. And like others, it's used to pass down data (such as theme here).

To use it, you have to wrap any widget above your ListTile with a ListTileTheme containing the desired values.

ListTile will then theme itself depending on the closest ListTileTheme instance.

Wrap ListTile in an Ink .

Ink(
  color: isSelected ? Colors.blue : Colors.transparent,
  child: ListTile(title: Text('hello')),
)

This is no more pain!

Now you can use tileColor and selectedTileColor property of ListTile widget to achieve it.

Have a look at this Issue #61347 which got merged into master.

An easy way would be to store the initial index in a variable and then change the state of that variable whenever tapped.

   ListView.builder(
              shrinkWrap: true,
              itemCount: 4,
              itemBuilder: (context, index) {
                return Container( //I have used container for this example. [not mandatory]
                    color: tappedIndex == index ? Colors.blue : Colors.grey,
                    child: ListTile(
                        title: Center(
                      child: Text('${index + 1}'),
                    ),onTap:(){
                          setState((){
                            tappedIndex=index;
                          });
                        }));
              })

full code:

import 'package:flutter/material.dart';

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

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

class MyWidget extends StatefulWidget {
  @override
  MyWidgetState createState() => MyWidgetState();
}

class MyWidgetState extends State<MyWidget> {
  late int tappedIndex;

  @override
  void initState() {
    super.initState();
    tappedIndex = 0;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
          ListView.builder(
              shrinkWrap: true,
              itemCount: 4,
              itemBuilder: (context, index) {
                return Container(
                    color: tappedIndex == index ? Colors.blue : Colors.grey,
                    child: ListTile(
                        title: Center(
                      child: Text('${index + 1}'),
                    ),onTap:(){
                          setState((){
                            tappedIndex=index;
                          });
                        }));
              })
        ]));
  }
}

Dartpad link: https://dartpad.dev/250ff453b97cc79225e8a9c657dffc8a

I know that the original question has been answered, but I wanted to add how to set the color of ListTile while the tile is being pressed . The property you are looking for is called highlight color and it can be set by wrapping the ListTile in a Theme widget, like this:

Theme(
  data: ThemeData(
    highlightColor: Colors.red,
  ),
  child: ListTile(...),
  )
);

Note: if the Theme widget resets the font of text elements inside the ListTile , just set its fontFamily property to the same value You used in other places in your app.

Unfortunately, ListTile doesn't have background-color property. Hence, we have to simply wrap the ListTile widget into a Container/Card widget and then we can use its color property. Further, We have to provide SizedBox widget with some height to separate the same colored ListTiles.

I am sharing that worked for me :)

I hope it will definitely help you.

Screenshot: see how it works

            return 
              ListView(
                children: snapshot.data.documents.map((doc) {
                  return Column(children: [
                    Card(
                      color: Colors.grey[200],
                       child: ListTile(
                      leading: Icon(Icons.person),
                      title: Text(doc.data['coursename'], style: TextStyle(fontSize: 22),),
                      subtitle: Text('Price: ${doc.data['price']}'),
                      trailing: IconButton(
                        icon: Icon(Icons.delete),
                        onPressed: () async {
                          await Firestore.instance
                              .collection('courselist')
                              .document(doc.documentID)
                              .delete();
                        },
                      ),
                  ),
                    ),
                 SizedBox(height: 2,)
                  ],);
                }).toList(),[enter image description here][1]
              );

I have used as

ListTile(
                title: Text('Receipts'),
                leading: Icon(Icons.point_of_sale),
                tileColor: Colors.blue,
              ),  

There are two props: tileColor and selectedTileColor.

tileColor - when the tile/row is Not selected;

selectedTileColor - when the tile/row is selected

ListTile(
        selected: _isSelected,
        tileColor: Colors.blue,
        selectedTileColor: Colors.greenAccent,
)

I was able to change the Background Color of ListTile by making it a child of Container Widget and adding color to the Container Widget.

Here drawerItem is the model class which holds the isSelected value. Color of background depends on isSelected value.

Note: For unselected items keep the color Transparent so you will still get the ripple effect.

 for (var i = 0; i < drawerItems.length; i++) {
      var drawerItem = drawerItems[i];
      drawerOptions.add(new Container(
        color: drawerItem.isSelected
            ? Colors.orangeAccent
            : Colors.transparent,
        child: new ListTile(
          title: new Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[Text(drawerItem.title), drawerItem.count],
          ),
          leading: SvgPicture.asset(
            drawerItem.icon,
            width: 34,
            height: 34,
          ),
          onTap: () {
            _handleNavigation(i);
          },
          selected: drawerItem.isSelected,
        ),
      ));
    }

在此处输入图像描述

Your answer has been answered in Github .

Card(
  color: Colors.white,
  shape: ContinuousRectangleBorder(
    borderRadius: BorderRadius.zero,
  ),
  borderOnForeground: true,
  elevation: 0,
  margin: EdgeInsets.fromLTRB(0,0,0,0),
  child: ListTile(
    // ...
  ),
)

enter image description here >Make variable

        int slectedIndex;

on tap

     onTap:(){
                      setState(() {
                      selectedIndex=index;
                     })

Tile property

            color:selectedIndex==index?Colors.red :Colors.white,

Same As in List View Builder

        ListView.builder(
                          itemCount: 10,
                          scrollDirection:Axis.vertical,
                          itemBuilder: (context,index)=>GestureDetector(
                            onTap:(){
                              setState(() {
                                selectedIndex=index;
                              });
                              
                            } ,
                            child: Container(
                              margin: EdgeInsets.all(8),
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(5),
                                color:selectedIndex==index?Colors.red :Colors.white,
                              ),)

Use the Material widget with InkWell Widget then put inside it the ListTile as shown here in this example:

return Material(
      color: Colors.white,
      child: ListTile(
          hoverColor: Colors.greenAccent,
          onLongPress: longPressCallback,
          title: Text(
            '$taskTitle',
            style: TextStyle(
                decoration: isChecked
                    ? TextDecoration.lineThrough
                    : TextDecoration.none),
          ),
          trailing: Checkbox(
              activeColor: Colors.lightBlueAccent,
              value: isChecked,
              onChanged: checkboxCallback)),
    );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM