如何使用 ListView 更改在 flutter 中点击的按钮颜色

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

我已经使用 ListView.builder 创建了按钮,现在我想如果我点击任何按钮,那么只有那个按钮的颜色应该改变,但是当我点击任何按钮时,所有按钮的颜色都会改变。

这是代码

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

如果有人知道如何做到这一点,请提供帮助。

使用 int 类型来标记点击按钮,

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

最简单的方法是在单独的小部件中提取按钮逻辑。但是,如果您需要顶部小部件中的每个 pressAttentions 值,这将不起作用。

无论如何,这是最简单的方法:

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

如果您需要 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),
              ),
            ),
          );
        }
      ),
    );
  }
}

作为奖励,如果您希望一次只选择 1 个按钮:

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

附带说明:您的命名似乎有问题:

  • 你是否使用驼峰式命名属性(差:litems,好:lItems
  • DO start your bool variables be is or has: (BAD: pressAttention, GOOD: hasPressedAttention)

尝试下面的代码希望它对你有所帮助,并且使用 ElevatedButton 而不是 RaisedButton 的一件事是因为当前的 flutter 版本 RaisedButton Widget 已被删除。 ElevatedButton

声明 int var 和您的列表:

int? tappedIndex; 

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

声明 initState() 方法

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

您的小部件:

 return Scaffold(
  body: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      ListView.builder(
          shrinkWrap: true,
          itemCount: litems.length,
          itemBuilder: (context, index) {
            return Container(
              child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    shape: RoundedRectangleBorder(
                      borderRadius: new BorderRadius.circular(30.0),
                    ),
                    primary: tappedIndex == index
                        ? Colors.blue
                        : Colors.transparent,
                  ),
                  child: Center(
                    child: Text(litems[index]),
                  ),
                  onPressed: () {
                    setState(() {
                      tappedIndex = index;
                    });
                  }),
            );
          }),
    ],
  ),
);

完整代码:

import 'package:flutter/material.dart';
    void main() {
  runApp(
    MaterialApp(
      home: Material(
        child: Search(),
      ),
    ),
  );
}
class Search extends StatefulWidget {
  const Search({Key? key}) : super(key: key);

  @override
  State<Search> createState() => _SearchState();
}

class _SearchState extends State<Search> {
  int? tappedIndex;
  List<String> litems = [
    "Counter No 1",
    "Counter No 2",
    "Counter No 3",
    "Counter No 4"
  ];

  @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: litems.length,
              itemBuilder: (context, index) {
                return Container(
                  child: ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        shape: RoundedRectangleBorder(
                          borderRadius: new BorderRadius.circular(30.0),
                        ),
                        primary: tappedIndex == index
                            ? Colors.blue
                            : Colors.transparent,
                      ),
                      child: Center(
                        child: Text(litems[index]),
                      ),
                      onPressed: () {
                        setState(() {
                          tappedIndex = index;
                        });
                      }),
                );
              }),
        ],
      ),
    );
  }
}

您的结果屏幕->