Home > Mobile >  how to change button color of that which is tapped in flutter using ListView
how to change button color of that which is tapped in flutter using ListView

Time:10-05

I have created buttons using ListView.builder, now i want if i tapped on any button than only that button color should change, but when i tap on any button all buttons color are changing.

here is the code

List<String> litems = ["Counter No 1", "Counter No 2", "Counter No 3", "Counter No 4"];
bool pressAttention=false;

 Widget build(BuildContext context) {
    return SafeArea(
        child: SingleChildScrollView(
                SizedBox(
                  height: MediaQuery.of(context).size.height,
                  child: ListView.builder(
                      shrinkWrap: true,
                      itemCount: litems.length,
                      itemBuilder: (BuildContext ctxt, int index) {
                        return Column(
                          children: [
                            Container(
                              height: 55.0,
                              width: MediaQuery.of(context).size.width*0.9,
                              child: new RaisedButton(
                              child: new Text(litems[index]),
                              textColor: Colors.white,
                              shape: new RoundedRectangleBorder(
                                borderRadius: new BorderRadius.circular(30.0),
                              ),
                              color: pressAttention ? Colors.green : Colors.grey,
                              onPressed: () => setState(() => pressAttention = !pressAttention), 
                      ),

                      
                            ),
                            SizedBox20(),
                          ],
                        );
                        
                      }),
                      
                  ),
);
  }
}

please help if any one know how to do this.

CodePudding user response:

The simplest way to do this is to extract the button logic in a separate widget. However this will not work if you need every pressAttentions values in the top widget.

Anyway, here is the simplest way:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: Material(child: MyApp())));
}

class MyApp extends StatelessWidget {
  final List<String> litems = ["Counter No 1", "Counter No 2", "Counter No 3", "Counter No 4"];

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: ListView.builder(
        shrinkWrap: true,
        itemCount: litems.length,
        itemBuilder: (context, index) {
          return MyButton(title: litems[index]);
        }
      ),
    );
  }
}

class MyButton extends StatefulWidget {
  final String title;

  const MyButton({
    Key? key,
    required this.title,
  }) : super(key: key);

  @override
  State<MyButton> createState() => _MyButtonState();
}

class _MyButtonState extends State<MyButton> {
  // Default to non pressed
  bool pressAttention = false;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 20.0),
      child: Container(
        height: 55.0,
        width: MediaQuery.of(context).size.width * 0.9,
        child: new RaisedButton(
          child: new Text(widget.title),
          textColor: Colors.white,
          shape: new RoundedRectangleBorder(
            borderRadius: new BorderRadius.circular(30.0),
          ),
          color: pressAttention ? Colors.green : Colors.grey,
          onPressed: () => setState(() => pressAttention = !pressAttention),
        ),
      ),
    );
  }
}

Here is the way if you need to have the list of pressAttentions:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: Material(child: MyApp())));
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final List<String> litems = ["Counter No 1", "Counter No 2", "Counter No 3", "Counter No 4"];

  // Initialize with the same length as litems and with only falses
  late List<bool> pressedAttentions = litems.map((e) => false).toList();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: ListView.builder(
        shrinkWrap: true,
        itemCount: litems.length,
        itemBuilder: (context, index) {
          final pressAttention = pressedAttentions[index];

          return Padding(
            padding: const EdgeInsets.only(bottom: 20.0),
            child: Container(
              height: 55.0,
              width: MediaQuery.of(context).size.width * 0.9,
              child: new RaisedButton(
                child: new Text(litems[index]),
                textColor: Colors.white,
                shape: new RoundedRectangleBorder(
                  borderRadius: new BorderRadius.circular(30.0),
                ),
                color: pressAttention ? Colors.green : Colors.grey,
                onPressed: () => setState(() => pressedAttentions[index] = !pressAttention),
              ),
            ),
          );
        }
      ),
    );
  }
}

As a bonus, here is if you want only 1 button at a time only to be selected:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: Material(child: MyApp())));
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final List<String> litems = ["Counter No 1", "Counter No 2", "Counter No 3", "Counter No 4"];

  // Initialize to -1 so that none are selected
  // If you want to select the first by default you could change this to 0
  int pressedAttentionIndex  = -1;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: ListView.builder(
        shrinkWrap: true,
        itemCount: litems.length,
        itemBuilder: (context, index) {
          final pressAttention = pressedAttentionIndex == index;

          return Padding(
            padding: const EdgeInsets.only(bottom: 20.0),
            child: Container(
              height: 55.0,
              width: MediaQuery.of(context).size.width * 0.9,
              child: new RaisedButton(
                child: new Text(litems[index]),
                textColor: Colors.white,
                shape: new RoundedRectangleBorder(
                  borderRadius: new BorderRadius.circular(30.0),
                ),
                color: pressAttention ? Colors.green : Colors.grey,
                onPressed: () => setState(() => pressedAttentionIndex = index),
              ),
            ),
          );
        }
      ),
    );
  }
}

As a side note: You seem to have issues with your naming:

  • DO you camelCase to name attributes (BAD: litems, GOOD: lItems)
  • DO start your bool variables be is or has: (BAD: pressAttention, GOOD: hasPressedAttention)

CodePudding user response:

Try below code hope its help to you and one thing used ElevatedButton instead of RaisedButton because current flutter version RaisedButton Widget is depricated. Image

CodePudding user response:

using type int to mark tapped button,

List<String> litems = ["Counter No 1", "Counter No 2", "Counter No 3", "Counter No 4"];

late int tapIndex;

  @override
  void initState() {
    super.initState();
    tapIndex = litems.length; // make sure no buttons are clicked in the initial state
  }

 Widget build(BuildContext context) {
    return SafeArea(
        child: SingleChildScrollView(
                SizedBox(
                  height: MediaQuery.of(context).size.height,
                  child: ListView.builder(
                      shrinkWrap: true,
                      itemCount: litems.length,
                      itemBuilder: (BuildContext ctxt, int index) {
                        return Column(
                          children: [
                            Container(
                              height: 55.0,
                              width: MediaQuery.of(context).size.width*0.9,
                              child: new RaisedButton(
                              child: new Text(litems[index]),
                              textColor: Colors.white,
                              shape: new RoundedRectangleBorder(
                                borderRadius: new BorderRadius.circular(30.0),
                              ),
                              color: tapIndex == index ? Colors.green : Colors.grey,
                              onPressed: () => setState(() => tapIndex = index), 
                      ),

                      
                            ),
                            SizedBox20(),
                          ],
                        );
                        
                      }),
                      
                  ),
);
  }
}

  • Related