Home > Enterprise >  Flutter ListView.builder management with Getx
Flutter ListView.builder management with Getx

Time:05-26

I'm at the beginning of learning Getx and I'm having the following problem: I have a ListView.builder with the CodeLine() widget, which is a widget where you can select it with an onLongPress. The idea here is to select a row but when I give onLongPress, all the rows are selected together.

class CodeEditor extends GetView<CodeEditorController> {
  const CodeEditor({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    ScrollController scrollCode = ScrollController();

    return Padding(
      padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 120.0),
      child: ListView.builder(
        controller: scrollCode,
        itemCount: 10,
        itemBuilder: (BuildContext context, int index){
          return CodeLine();
        }
      )
    );
  }
}

In CodeLine I have isSelected variable to show on screen when it is selected or not and I change its value in CodeLineController controller

class CodeLine extends GetView<CodeLineController> {
  CodeLine({Key? key}) : super(key: key);

  @override
  final controller = Get.put(CodeLineController());

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: GetX<CodeLineController>(
        builder: (_){
          return !_.isHidden ? Container(
            color: _.isSelected ? const Color(0x327a7a7a) : Colors.transparent,
            height: 35.0,
            child: Row(
              children: <Widget>[
                SizedBox(
                  width: 25.0,
                  child: Text(
                    "1",
                    textAlign: TextAlign.end,
                    style: TextStyle(
                      color: codeLineTheme.hintColor,
                      fontSize: 15.0,
                      fontWeight: FontWeight.bold
                    )
                  )
                ), 
                const SizedBox(width: 7.5),
                const Expanded(
                  child: SizedBox()
                )
              ]
            )
          ) : const SizedBox();
        }
      ),
      onLongPress: (){
        controller.isSelected = !controller.isSelected;
      }
    );
  }
}

In CodeLineController I have the isSelected variable as observable but when I change its boolean value, this value of all CodeLine instances is also changed, how can I change only the isSelected variable of a specific CodeLine?

class CodeLineController extends GetxController{
  CodeLineController();

  final _isHidden = false.obs;
  get isHidden => _isHidden.value;
  set isHidden(value) => _isHidden.value = value;

  final _isSelected = false.obs;
  get isSelected => _isSelected.value;
  set isSelected(value) => _isSelected.value = value;

}

CodePudding user response:

When you call a class that you extend with GetxController with Get.put, only one of that object is found in the project. And you always define the same object in the CodeLine widget. So a change affects all of its widgets. You can solve your problem like this: Add Map inside CodeLineController. Save all CodeLine widgets you reproduced with ListView to the map with a special key.

class CodeLineController extends GetxController {

  final RxMap<Key, bool> _map = <Key, bool>{}.obs;

  void setKey(Key key, bool value) {
    _map[key] = value;
  }

  void changeValue(Key key) {
    if (_map[key] != null) {
      _map[key] = !_map[key]!;
    }
  }

  bool getValue(Key key) {
    if (_map[key] != null) {
      return _map[key]!;
    } else {
      return false;
    }
  }
...
}

It can be an int "index" value instead of the "key" in the Map or a unique data you want.

You can pass "key" as a parameter to the CodeLine class.

class CodeLine extends GetView<CodeLineController> {
  final Key myKey;

  CodeLine({
    Key? key,
    required this.myKey,
  }) : super(key: key);
...
}

When creating the CodeLine class, pass the key as a parameter inside the ListView.

...
Key myKey;

return Padding(
...
itemBuilder: (BuildContext context, int index) {
  myKey = GlobalKey();
  controller.setKey(myKey, false);

  return CodeLine(myKey: myKey);
},
...

onLongPress

...
onLongPress: () {
  controller.changeValue(myKey);
},
...

This is how you can check

...
Container(
  color: controller.getValue(myKey)
      ? const Color(0x327a7a7a)
      : Colors.transparent,
...
  • Related