Solved: How to handle selected item for dynamically generated ListView in Flutter

Question

Asked by Shaon on November 05, 2021 (source).

final variationMap = HashMap<String, List>();

In this map, I have

key -> ["color"] = value -> ["White", "Black"]; key -> ["ram"] = value -> ["128GB", "256GB"];

Based on this information I have designed the below UI.

Bottom Sheet UI

**I want -> If I select white, white will be selected and black will remain unselected. And If I select black white will become unselected. The same goes for Ram. Selecting one will make the other unselected. Two list view selections will work independently. **

For a single list view, we can achieve this using a selectedIndex variable.

Here is the API response. Here attribute value can be multiple. But I need to show one value in UI. So after some logic, I store the label and value into a map.

"productVariation": [
        {
          "price": 406089.25,
          "qty": 449,
          "variationAttribute": [
            {
              "attribute_value": "White",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Color"
                  }
                ]
              }
            },
            {
              "attribute_value": "128GB",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Ram"
                  }
                ]
              }
            }
          ]
        },
        {
          "price": 292561.69,
          "qty": 246,
          "variationAttribute": [
            {
              "attribute_value": "White",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Color"
                  }
                ]
              }
            },
            {
              "attribute_value": "256GB",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Ram"
                  }
                ]
              }
            }
          ]
        },
        {
          "price": 951456.88,
          "qty": 828,
          "variationAttribute": [
            {
              "attribute_value": "Black",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Color"
                  }
                ]
              }
            },
            {
              "attribute_value": "128GB",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Ram"
                  }
                ]
              }
            }
          ]
        },
        {
          "price": 930735.09,
          "qty": 321,
          "variationAttribute": [
            {
              "attribute_value": "Black",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Color"
                  }
                ]
              }
            },
            {
              "attribute_value": "256GB",
              "attributeDetails": {
                "attributeLabel": [
                  {
                    "label": "Ram"
                  }
                ]
              }
            }
          ]
        }
      ]

Here is the UI code. This code is for the bottom sheet dialog.

variationView() {
    final widgets = <Widget>[];

    var i = 1; // maintain vertical dot line between variation
    for (var key in widget.controller.variationMap.keys) {
      final list = widget.controller.variationMap[key];

      widgets.add(
        GlobalText(
          str: "Select $key",
          fontSize: 18,
          fontWeight: FontWeight.w300,
        ),
      );

      widgets.add(
        const SizedBox(
          height: 20,
        ),
      );

      widgets.add(
        SizedBox(
          height: 60,
          child: ListView.builder(
            itemCount: list!.length,
            shrinkWrap: true,
            scrollDirection: Axis.horizontal,
            itemBuilder: (ctx, index) {
              return GestureDetector(
                onTap: () {
                  setState(() {
                    isSelectedIndex = index;
                    isSelectedIndexForListView = i;
                  });
                },
                child:Container(
                  margin: EdgeInsets.only(right: 11),
                  padding: EdgeInsets.all(4),
                  width: 60,
                  height: 55,
                  decoration: BoxDecoration(
                    color: Color(0xfff8f8f8),
                    borderRadius: BorderRadius.circular(10),
                    border: Border.all(
                      color: isSelectedIndex == index && isSelectedIndexForListView == i
                      
                          ? Colors.black
                          : Color(0xffe2e2e2),
                      width: 1,
                    ),
                  ),
                  child: Center(
                    child: GlobalText(
                      str: list[index],
                      color: Color(0xff535960),
                      fontSize: 13,
                      fontWeight: FontWeight.w400,
                      maxLines: 2,
                    ),
                  ),
                ),
              );
            },
          ),
        ),
      );

      if (i < widget.controller.variationMap.keys.length) {
        widgets.add(
          const SizedBox(
            height: 30,
          ),
        );
      }

      i++;
    }

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: widgets,
    );
  }

I have tried multiple ways but failed to hold or manage the state of the selected item.

In this code, I have tried to hold the index of the list view and another for item selected index. but When I select a ram, So same index color also goes selected and vice versa.

I have also tried using Unique key. But failed to solve the problem.

Answer

Question answered by Inan M (source).

First you can create a model class for Value which will have to fields one for the value name another for checking if it's selected or not.

class Value{

     String valueName;
     bool isSelected;

}

Then create another class which will have one field of String type that is the label and another field of type List of Value object.

class Model {

  String label;
  List<Value> valueList;

}

From your controller or viewmodel class or the class you are using to update the states you will just have to update the value of isSelected field.

FLUTTER FLUTTER-LISTVIEW LISTVIEW
SHARE: