Checkbox UI未更新,尽管复选框的项目值已更新,GetX颤动

发布于 2025-02-03 00:56:23 字数 3718 浏览 4 评论 0原文

获取工作代码示例”此处

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

我正在尝试实现简单的多选择网格视图,但是在单击复选框时,所选属性更改,但不会反射回UI, 如果我刷新它将更新。

我尝试了obx()=> ();小部件,它仍然没有更新

我的产品控制器

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()添加到父母无济于事。

在下面的代码这里这只是问题和问题所面临的。

enter image description here

Get the working code sample here

I have an RxList of addOnProducts which contains product and selected attributes.

I am trying to implement the simple multiSelectable grid View, but on clicking the checkBox the selected attribute changes but it is not reflected back to the ui,
If i refresh it will be updated.

I tried Obx()=> (); widget , It is still not updating

My ProductController

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

My Grid View

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

Therefore in the console it is :

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

But the checkBox is not updating, it updates only when i refresh, How to overCome this? Adding Obx() to the parent isn't helping..

Find the github link to code below here which has just the question and and the problem faced..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陪我终i 2025-02-10 00:56:23

经过代码后。我已经实施了以下以下情况,它将在没有热重加载的情况下改变状态:

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

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

接下来,我已经更改了您的网格类以生成产品窗口小部件的列表,作为AddProduct List长度的大小。在我看来,这是一种写格里视图的更好方法。从您的GridView中删除OBX,并在使用GETX时将您的状态小部件更改为无状态的小部件。即使在无状态的小部件中,它也会管理您的状态。在此处添加您的产品控制器,因为您将从控制器类访问AddProduct List。

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

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

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类需要所需的值索引。因此,小部件知道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中使用GetX有2个应用程序,但我仍然会不时浏览文档。他们有关于如何管理状态的明确文件。

After going through your code. I've implemented the following that will change state without hot reload:

In your main dart you do not need to put your product controller here as you are not using it

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

Next, I have changed your grid class to generate a list of product widget as the size of the addProduct list length. In my opinion this is a better way to write GridView counts children. Remove obx from your gridview and change your stateful widget to stateless as you are using Getx. It will manage your state even in a stateless widget. Add your product controller here as you will access addProduct list from the controller 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))
      ),
    );
  }
}

In your product controller class, remove the instance as it is not important. That is the only change here:

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

Lastly, your productWidget class needs a required value index. So, the widget knows which index in gridview the user is clicking and use Obx() here in checkbox as you have an observable value selected here. Remember to always use Obx() when you have an obs value. This will update the widget whenever an obs value changes. Here, if you notice we are using Get.find() instead of Put as Get.put is already inside the scope so all you need to do is find the controller that you will use. You can find or put multiple controllers and update values as much as you want.

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

Go through GetX documentation for proper use of GetX. Even though I have 2 apps in Playstore with GetX, I still go through documentation from time to time. They have a clear documentation on how to manage state.

酒中人 2025-02-10 00:56:23

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

In ProductWidget adding an additional Obx() solved my problem

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());
                },
              ),))
            ),
          ],
        ));
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文