CheckBox ui 未更新,但复选框的项目值已更新,Getx 颤振

CheckBox ui is not updated though the item value of checkbox is updated, Getx flutter

获取工作代码示例here

我有一个 RxListaddOnProducts,其中包含 productselected 属性。

我正在尝试实现简单的 multiSelectable 网格视图,但是在单击复选框时,选定的属性会发生变化,但不会反映回 ui, 如果我刷新它会更新。

我试过Obx()=>(); widget , 还没更新

我的产品控制器

class ProductsController extends GetxController {
  late Worker worker;
  static ProductsController instance = Get.find();
  RxList<ProductModel> products = RxList<ProductModel>([]);
  RxList<CheckProduct> addOnProducts = <CheckProduct>[].obs;
  String collection = "products";
  @override
  void onReady() {
    super.onReady();
    products.bindStream(getAllProducts());
    worker = once(products, (List<ProductModel> value) {
      fillAddOnProducts(value);
    }, condition: () => products.isNotEmpty);
  }


  Stream<List<ProductModel>> getAllProducts() => FirebaseFirestore.instance
      .collection(collection)
      .snapshots()
      .map((query) => query.docs
          .map((item) => ProductModel.fromMap(item.data(), item.id))
          .toList());
 
  void fillAddOnProducts(List<ProductModel> products) => {
        products.forEach((element) {
          addOnProducts.add(CheckProduct(product: element, selected: false));
        })
      };
}

class CheckProduct {
  ProductModel product;
  bool selected;
  CheckProduct(
      {required ProductModel this.product, required bool this.selected});
}

我的网格视图

class AddOns extends StatelessWidget {
  const AddOns({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          actions: [],
          title: Text("Select Addons"),
        ),
        body: Obx(() => GridView.count(
              crossAxisCount: 2,
              children: productsController.addOnProducts
                  .map((element) => ProductWidget(product: element))
                  .toList(),
            )));
  }
}

class ProductWidget extends StatelessWidget {
  final CheckProduct product;
  const ProductWidget({Key? key, required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.yellow,
        margin: EdgeInsets.all(10),
        child: Stack(
          alignment: Alignment.center,
          children: [
            Positioned(
              top: 4,
              left: 4,
              child: Checkbox(
                value: product.selected,
                onChanged: (value) {
                  print("value of the value is : $value");
                  print("value of product selected before is: " +
                      product.selected.toString());
                  product.selected = value!;
                  print("value of product selected after is: " +
                      product.selected.toString());
                },
              ),
            ),
          ],
        ));
  }
}

因此在控制台中是:

I/flutter (20067): value of the value is : true
I/flutter (20067): value of product selected before is: false
I/flutter (20067): value of product selected after is: true

但是复选框没有更新,只有刷新时才会更新,如何克服这个问题?将 Obx() 添加到父级没有帮助..

here 下方找到 github link 的代码,其中只有问题和面临的问题..

通过你的代码后。我已经实现了以下无需热重载即可更改状态的方法:

在您的主要飞镖中,您不需要将产品控制器放在这里,因为您没有使用它

main.dart

import 'package:flutter/material.dart';

import 'grid.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: GridSelect(),
    );
  }
}

接下来,我更改了您的网格 class 以生成产品小部件列表作为 addProduct 列表长度的大小。在我看来,这是编写 GridView 计数子项的更好方法。从您的 gridview 中删除 obx 并将您的有状态小部件更改为无状态,因为您正在使用 Getx。即使在无状态小部件中,它也会管理您的状态。在此处添加您的产品控制器,因为您将从控制器访问 addProduct 列表 class。

grid.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:test_project/controllers/productController.dart';
import 'package:test_project/productWidget.dart';

class GridSelect extends StatelessWidget {
  final _controller = Get.put(ProductController());
  GridSelect({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.count(
        crossAxisCount: 2,
        children: List.generate(_controller.addOnProducts.length, (index) => ProductWidget(index: index))
      ),
    );
  }
}

在您的产品控制器中 class,删除该实例,因为它不重要。这是这里唯一的变化:

ProductController.dart

import 'package:get/get.dart';
import 'package:test_project/models/productModel.dart';

class ProductController extends GetxController {
  RxList<CheckProduct> addOnProducts = <CheckProduct>[].obs;

  @override
  void onReady() {
    super.onReady();
    addOnProducts.add(CheckProduct(product: ProductModel('productOne', 20)));
    addOnProducts.add(CheckProduct(product: ProductModel('productTwo', 25)));
    addOnProducts.add(CheckProduct(product: ProductModel('productThree', 30)));
    addOnProducts.add(CheckProduct(product: ProductModel('productFour', 40)));
  }
}

class CheckProduct {
  ProductModel product;
  RxBool selected = false.obs;
  CheckProduct({
    required this.product,
  });
}

最后,您的 productWidget class 需要一个必需的值索引。因此,小部件知道用户正在单击 gridview 中的哪个索引,并在此处的复选框中使用 Obx(),因为您在此处选择了一个可观察值。当您有一个 obs 值时,请记住始终使用 Obx() 。这将在 obs 值更改时更新小部件。在这里,如果您注意到我们使用 Get.find() 而不是 Put,因为 Get.put 已经在范围内,所以您需要做的就是找到您将使用的控制器。您可以根据需要查找或放置多个控制器并更新值。

productWidget.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:test_project/controllers/productController.dart';

class ProductWidget extends StatelessWidget {
  final ProductController _controller = Get.find();
  final int index;
  ProductWidget({Key? key, required this.index}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return Container(
      color: Colors.yellow,
      margin: EdgeInsets.all(20),
      child: Stack(
        alignment: Alignment.center,
        children: [
          Positioned(
            top: 4,
            left: 4,
            child: Obx(()=>Checkbox(
              value: _controller.addOnProducts[index].selected.value,
              onChanged: (value) {
                print("value of the value is : $value");
                print("value of product selected before is: " +
                    _controller.addOnProducts[index].selected.toString());
                _controller.addOnProducts[index].selected.value = value!;
                print("value of product selected after is: " +
                    _controller.addOnProducts[index].selected.toString());
              },
            )),
          )
        ],
      ),
    );
  }
}

阅读 GetX 文档以正确使用 GetX。尽管我在 Playstore 中有 2 个带有 GetX 的应用程序,但我仍然会不时查看文档。他们有关于如何管理状态的清晰文档。

在 ProductWidget 中添加一个额外的 Obx() 解决了我的问题

class ProductWidget extends StatelessWidget {
  final CheckProduct product;
  const ProductWidget({Key? key, required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.yellow,
        margin: EdgeInsets.all(10),
        child: Stack(
          alignment: Alignment.center,
          children: [
            Positioned(
              top: 4,
              left: 4,
             // Even the child needs Obx() ; The parent's Obx() is not reflected here
              child: Obx(()=>(Checkbox( 
                value: product.selected,
                onChanged: (value) {
                  print("value of the value is : $value");
                  print("value of product selected before is: " +
                      product.selected.toString());
                  product.selected = value!;
                  print("value of product selected after is: " +
                      product.selected.toString());
                },
              ),))
            ),
          ],
        ));
  }