使用 Getx 进行 Flutter ListView.builder 管理

Flutter ListView.builder management with Getx

我刚开始学习 Getx,我遇到了以下问题:我有一个带有 CodeLine() 小部件的 ListView.builder,您可以在其中 select它与一个 onLongPress。这里的想法是 select 一行,但是当我给 onLongPress 时,所有行都 select 在一起。

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

在 CodeLine 中,我有 isSelected 变量在 selected 或未编辑时显示在屏幕上,我在 CodeLineController 控制器中更改它的值

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

在 CodeLineController 中,我将 isSelected 变量作为可观察变量,但是当我更改它的布尔值时,所有 CodeLine 实例的此值也会更改,我如何才能仅更改特定 CodeLine 的 isSelected 变量?

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;

}

当您使用 Get.put 调用使用 GetxController 扩展的 class 时,在项目中只能找到该对象之一。而且您始终在代码行小部件中定义相同的对象。因此,更改会影响其所有小部件。你可以这样解决你的问题: 在 CodeLineController 中添加地图。使用特殊键将您使用 ListView 复制的所有 CodeLine 小部件保存到地图。

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;
    }
  }
...
}

它可以是一个int“index”值而不是Map中的“key”或者你想要的唯一数据。

您可以将“key”作为参数传递给代码行class。

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

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

创建代码行时 class,将键作为参数传递到 ListView 中。

...
Key myKey;

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

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

长按

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

这是您检查的方式

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