简体   繁体   English

如何在onTap上为选定的ListItem着色

[英]How to color selected ListItem onTap

I want to color select value from a ListView like this : 我想像这样从ListView中为值选择颜色:

在此处输入图片说明

The problem is I print all when I try it , code : 问题是我尝试时全部打印,代码:

class _ProcedureList extends State<ProcedureList> {

bool isSelected  = true;

   _isSelected() {
    setState(() {
      if (isSelected) {
        isSelected = false;
      } else {
        isSelected = true;
      }
    });
  }



  @override
  Widget build(BuildContext context) {
    var procedureList = widget.filteredkits
        .where((kit) => kit.brand == widget.brand)
        .map((kit) => kit.procedure)
        .toSet()
        .toList();

    return Expanded(
      flex: 2,
      child: Container(
        padding: EdgeInsets.only(left: 35.0),
        child: new ListView.builder(
          itemCount: procedureList.length,
          itemBuilder: (BuildContext context, int index) {
            return Padding(
              padding: EdgeInsets.all(6.0),
              child: Column(
                children: <Widget>[
                  new Container(
                    width: 300.0,
                    height: 30.0,
                    color: Colors.grey[700],
                    padding: EdgeInsets.all(6.0),
                    child: new Text(widget.brand),
                  ),
                  GestureDetector(
                    onTap: () => widget.getProcedureSelectedandList(procedureList[index].toString()) & _isSelected(),
                    child: Container(
                      width: 300.0,
                      padding: EdgeInsets.all(3.0),
                      color: !isSelected ? Colors.white : Colors.orange,
                      child: 
                      new Text(procedureList[index])
                    ),
                  ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}

And this is what I achieve , all colored : 这就是我所实现的,全是彩色的:

在此处输入图片说明

I don't know how to only color one item when the event happens and if we can change the text color with the same event better . 我不知道如何在事件发生时只为一个项目着色,如果我们可以更好地改变同一事件的文字颜色。

you should have a isSelected value per every single item you have in the list an then when the user clicks on the one of the items in the list you will change the isSelected value just for taped item index and in the build statement you should do the action base on the isSelected value of the passed in index 您应该为列表中的每个项目都拥有一个isSelected值,然后,当用户单击列表中的一个项目时,您将只为录音项目索引更改isSelected值,并在build语句中执行基于传入索引的isSelected值的操作

here is example : 这是示例:

在此处输入图片说明

class MyListWidgetState extends State<MyListWidget> {
  List<String> items = ["A", "B", "C", "D", "E", "F"];

  Map<int, bool> itemsSelectedValue = Map();

  @override
  Widget build(BuildContext context) {
    return new ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          bool isCurrentIndexSelected = itemsSelectedValue[index] == null
              ? false
              : itemsSelectedValue[index];

          Container contianer;

          if (isCurrentIndexSelected) {
            contianer = new Container(
              alignment: Alignment.center,
              height: 100.0,
              color: Colors.blue,
              child: new Text(
                items[index],
                style: new TextStyle(color: Colors.red, fontSize: 18.0),
                textAlign: TextAlign.center,
              ),
            );
          } else {
            contianer = new Container(
              alignment: Alignment.center,
              height: 100.0,
              color: Colors.red,
              child: new Text(
                items[index],
                style: new TextStyle(color: Colors.blue, fontSize: 18.0),
                textAlign: TextAlign.center,
              ),
            );
          }

          return GestureDetector(
            onTap: () {
              print("${!isCurrentIndexSelected}");
              itemsSelectedValue[index] = !isCurrentIndexSelected;

              setState(() {
                print("OnClick : $index + ${itemsSelectedValue[index]}");
              });
            },
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: contianer,
            ),
          );
        });
  }
}

or you can create StateFull widget which keeps own isSelected Value for every item of your list like the below example : 或者您可以创建StateFull小部件,该小部件为列表中的每个项目保留自己的isSelected Value,如以下示例所示:

List<String> items = [
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "D",
  "J",
  "K",
  "L",
  "M",
  "P"
];

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new Scaffold(
          body: new ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return new SelectableWidget(
            new SelectableWidgetViewModel(
              items[index],
              isSelected: false,
            ),
          );
        },
      )),
    );
  }
}

class SelectableWidget extends StatefulWidget {
  final SelectableWidgetViewModel viewModel;

  SelectableWidget(this.viewModel);

  @override
  State<StatefulWidget> createState() {
    return SelectableWidgetState();
  }
}

class SelectableWidgetState extends State<SelectableWidget> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    Container container;

    if (widget.viewModel.isSelected) {
      container = new Container(
        alignment: Alignment.center,
        height: 100.0,
        color: Colors.blue,
        child: new Text(
          widget.viewModel.title,
          style: new TextStyle(color: Colors.red, fontSize: 18.0),
          textAlign: TextAlign.center,
        ),
      );
    } else {
      container = new Container(
        alignment: Alignment.center,
        height: 100.0,
        color: Colors.red,
        child: new Text(
          widget.viewModel.title,
          style: new TextStyle(color: Colors.blue, fontSize: 18.0),
          textAlign: TextAlign.center,
        ),
      );
    }

    return GestureDetector(
      onTap: () {
        setState(() {
          widget.viewModel.isSelected = !widget.viewModel.isSelected;
        });
      },
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: container,
      ),
    );
  }
}

class SelectableWidgetViewModel {
  bool isSelected;
  String title;

  SelectableWidgetViewModel(this.title, {this.isSelected = false});
}

i think second option is better for performance reasons 我认为由于性能原因,第二种选择更好

What you need to do is to refactor your code such that the widget that is being passed into the ListView builder function have it is own StatefulWidget . 您需要做的是重构代码,以使传递到ListView builder函数的小部件具有自己的StatefulWidget So move the widget tree inside the builder function into its own separate StatefulWidget and handle the state manipulation logic in there instead of ProcedureList . 因此,将构建器函数内的窗口小部件树移动到其自己的单独的StatefulWidget并在那里处理状态操纵逻辑,而不是ProcedureList The reason you are getting this behavior is because every instance that is generated from the ListView.builder is being exposed to the same state value of isSelected by moving your logic into a separate StatefulWidget each instance will have its own state. 之所以会出现这种行为,是因为通过将逻辑移到单独的StatefulWidget每个从ListView.builder生成的实例都处于isSelected的相同状态值,每个实例将具有自己的状态。

sorry for the late reply. 这么晚才回复很抱歉。 I have a better solution and i have changed in your code 我有一个更好的解决方案,并且我更改了您的代码

    class _ProcedureList extends State<ProcedureList> {



        int isSelected  = -1; // changed bool to int and set value to -1 on first time if you don't select anything otherwise set 0 to set first one as selected. 


       _isSelected(int index) { //pass the selected index to here and set to 'isSelected'
        setState(() {
            isSelected = index;
        });
      }



      @override
      Widget build(BuildContext context) {
        var procedureList = widget.filteredkits
            .where((kit) => kit.brand == widget.brand)
            .map((kit) => kit.procedure)
            .toSet()
            .toList();

    return Expanded(
      flex: 2,
      child: Container(
        padding: EdgeInsets.only(left: 35.0),
        child: new ListView.builder(
          itemCount: procedureList.length,
          itemBuilder: (BuildContext context, int index) {
            return Padding(
              padding: EdgeInsets.all(6.0),
              child: Column(
                children: <Widget>[
                  new Container(
                    width: 300.0,
                    height: 30.0,
                    color: Colors.grey[700],
                    padding: EdgeInsets.all(6.0),
                    child: new Text(widget.brand),
                  ),
                  GestureDetector(
                    onTap: () => widget.getProcedureSelectedandList(procedureList[index].toString()) & _isSelected(index), //pass index value to '_isSelected' 
                    child: Container(
                      width: 300.0,
                      padding: EdgeInsets.all(3.0),
                      color: isSelected != null && isSelected == index //set condition like this. voila! if isSelected and list index matches it will colored as white else orange.
                             ? Colors.white 
                             : Colors.orange,
                      child: 
                      new Text(procedureList[index])
                    ),
                  ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}

Still Confused check this blog 仍感到困惑检查此博客

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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