【问题标题】:Updating state of widget from another widget in flutter在颤动中从另一个小部件更新小部件的状态
【发布时间】:2021-03-25 17:22:33
【问题描述】:

我一直在flutter 中编写一个排序可视化器,到目前为止我能够动画块的移动。但我也想更新块的颜色,当块经历被扫描、移动和最后完全排序的状态时。我在 Flutter 中查找了 State management,不知道应该在我的项目中使用什么方法。
下面是 DashBoard Class

import 'package:algolizer/sortingAlgorithms/Block.dart';
import 'package:flutter/material.dart';
import 'dart:math';

class DashBoard extends StatefulWidget {
  double width;
  double height;
  DashBoard(@required this.width, @required this.height);
  @override
  _DashBoardState createState() => _DashBoardState();
}

class _DashBoardState extends State<DashBoard> {
  double currentSliderValue = 50;
  List<double> arr = new List(500);
  List<Block> blockList;
  bool running = false;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    fillArr((widget.width * 0.6) / 50, (widget.width * 0.1) / 50,
        widget.height * 0.7);
  }

  void InsertionSort() async {
    setState(() {
      running = true;
    });
    int delay = (pow(15, 4) / pow(currentSliderValue, 2)).round();
    for (int i = 1; i < currentSliderValue; i++) {
      if (blockList[i] == null) break;
      Block key = blockList[i];
      int j = i - 1;
      while (j >= 0 && blockList[j].height > key.height) {
        setState(() {
          blockList[j + 1] = blockList[j];
        });
        await Future.delayed(Duration(milliseconds: delay));
        j--;
      }
      blockList[j + 1] = key;
    }
    setState(() {
      running = false;
    });
  }

  void BubbleSort() async {
    setState(() {
      running = true;
    });
    int delay = (pow(15, 4) / pow(currentSliderValue, 2)).round();
    for (int i = 0; i < currentSliderValue - 1; i++) {
      for (int j = 0; j < currentSliderValue - i - 1; j++) {
        if (blockList[j].height > blockList[j + 1].height) {
          Block temp = blockList[j + 1];
          setState(() {
            blockList[j + 1] = blockList[j];
            blockList[j] = temp;
          });
          await Future.delayed(Duration(milliseconds: delay));
        }
      }
    }
    setState(() {
      running = false;
    });
  }

  // Map<String, >
  void fillArr(double width, double margin, double height) {
    for (int i = 0; i < arr.length; i++) arr[i] = null;
    var rng = new Random();
    for (int i = 0; i < currentSliderValue; i++) {
      double val = rng.nextDouble() * height;
      if (val == 0)
        continue;
      else
        arr[i] = val;
    }
    blockList = [...arr.map((height) => Block(height, width, margin))];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            SizedBox(height: 20),
            Row(
              children: [
                      Text(
                        "Length",
                      ),
                      Slider(
                          value: currentSliderValue,
                          min: 5,
                          max: 200,
                          onChanged: (double value) {
                            setState(() {
                              currentSliderValue = value;
                            });
                            double newwidth =
                                (MediaQuery.of(context).size.width * 0.6) /
                                    currentSliderValue;
                            double newmargin =
                                (MediaQuery.of(context).size.width * 0.1) /
                                    currentSliderValue;

                            fillArr(newwidth, newmargin, widget.height * 0.7);
                          }),
                      RaisedButton(
                        child: Text("Insertion Sort"),
                        onPressed: InsertionSort,
                      ),
                      RaisedButton(
                          onPressed: BubbleSort, child: Text("Bubble Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Merge Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Quick Sort")),
                      RaisedButton(
                          onPressed: () {}, child: Text("Counting Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Radix Sort")),
                      RaisedButton(
                          onPressed: () {}, child: Text("Selection Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Heap Sort")),
                    ],
            ),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [...blockList],
            ),
            // Row(
            //   children: [
            //     Container(
            //     child: Row(children: [
            //       Text("Algorithm")
            //     ],)
            //   )]
            // ),
          ],
        ),
      ),
    );
  }
}


这是Block 类:

import 'package:flutter/material.dart';

class Block extends StatefulWidget {
  Block(@required this.height, @required this.width, @required this.mar);
  double height;
  double width;
  double mar;
  @override
  _BlockState createState() => _BlockState();
}

class _BlockState extends State<Block> {
  Color col = Colors.blue;
  // void isKey() {
  //   setState(() {
  //     col = Colors.pink;
  //   });
  // }

  // void notKey() {
  //   setState(() {
  //     col = Colors.purple;
  //   });
  // }

  @override
  Widget build(BuildContext context) {
    return (widget.height == null)
        ? Container()
        : Container(
            height: this.widget.height,
            width: widget.width,
            margin: EdgeInsets.all(widget.mar),
            decoration: BoxDecoration(
              color: col,
            ),
          );
  }
}

【问题讨论】:

    标签: flutter dart state-management


    【解决方案1】:

    至于使用哪条状态管理路线,真的可以用其中任何一种方式完成。 GetX 对我来说是最简单的,而且样板文件最少。

    这是执行此操作的一种方法。我刚刚更新了 insertionSort 方法让您开始,您可以从那里开始。您在其他类中注意到的任何其他更改只是为了消除 linter 错误。

    您的所有方法和变量现在都可以存在于 GetX 类中。除了color,其余的现在都是可观察的流。

    class BlockController extends GetxController {
      RxDouble currentSliderValue = 50.0.obs; // adding .obs makes variable obserable
      RxList arr = List(500).obs;
      RxList blockList = [].obs;
      RxBool running = false.obs;
    
      Color color = Colors.red;
    
      void insertionSort() async {
        running.value = true; // adding .value access the value of observable variable
        color = Colors.blue;
        int delay = (pow(15, 4) / pow(currentSliderValue.value, 2)).round();
        for (int i = 1; i < currentSliderValue.value; i++) {
          if (blockList[i] == null) break;
          Block key = blockList[i];
          int j = i - 1;
          while (j >= 0 && blockList[j].height > key.height) {
            blockList[j + 1] = blockList[j];
            await Future.delayed(Duration(milliseconds: delay));
            j--;
          }
          blockList[j + 1] = key;
        }
        color = Colors.green;
        update(); // only needed for the color property because its not an observable stream
        running.value = false;
      }
    
      void bubbleSort() async {
        running.value = true;
        int delay = (pow(15, 4) / pow(currentSliderValue.value, 2)).round();
        for (int i = 0; i < currentSliderValue.value - 1; i++) {
          for (int j = 0; j < currentSliderValue.value - i - 1; j++) {
            if (blockList[j].height > blockList[j + 1].height) {
              Block temp = blockList[j + 1];
              blockList[j + 1] = blockList[j];
              blockList[j] = temp;
              await Future.delayed(Duration(milliseconds: delay));
            }
          }
        }
        running.value = false;
      }
    
      // Map<String, >
      void fillArr(double width, double margin, double height) {
        for (int i = 0; i < arr.length; i++) arr[i] = null;
        var rng = new Random();
        for (int i = 0; i < currentSliderValue.value; i++) {
          double val = rng.nextDouble() * height;
          if (val == 0)
            continue;
          else
            arr[i] = val;
        }
        blockList = [...arr.map((height) => Block(height, width, margin))].obs;
      }
    }
    

    在运行您的应用程序之前,在您的主程序中初始化控制器。通常,只要在您尝试访问控制器之前,它就可以在任何地方完成。

      Get.put(BlockController());
    

    这里是您不那么忙碌的DashBoard,因为所有这些逻辑都隐藏在 GetX 类中。在这里,我们找到了控制器,并使用它访问所有这些变量和方法。

    Obx 是根据更改重建的 GetX 小部件。

    class DashBoard extends StatefulWidget {
      final double width;
      final double height;
      DashBoard(this.width, this.height);
      @override
      _DashBoardState createState() => _DashBoardState();
    }
    
    class _DashBoardState extends State<DashBoard> {
      final controller = Get.find<BlockController>(); // finding same instance of BlockConroller that you initialized in `Main`
    
      @override
      void initState() {
        super.initState();
    
        controller.fillArr((widget.width * 0.6) / 50, (widget.width * 0.1) / 50,
            widget.height * 0.7);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Column(
              children: [
                SizedBox(height: 50),
                Obx(
                  // rebuilds when observable variables change
                  () => Column(
                    // changed to Column because a Row was overflowing
                    children: [
                      Text(
                        "Length",
                      ),
                      Slider(
                          value: controller.currentSliderValue.value,
                          min: 5,
                          max: 200,
                          onChanged: (double value) {
                              controller.currentSliderValue.value = value;                   
                            double newwidth =
                                (MediaQuery.of(context).size.width * 0.6) /
                                    controller.currentSliderValue.value;
                            double newmargin =
                                (MediaQuery.of(context).size.width * 0.1) /
                                    controller.currentSliderValue.value;
    
                            controller.fillArr(
                                newwidth, newmargin, widget.height * 0.7);
                          }),
                      RaisedButton(
                        child: Text("Insertion Sort"),
                        onPressed: controller.insertionSort,
                      ),
                      RaisedButton(
                          onPressed: controller.bubbleSort,
                          child: Text("Bubble Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Merge Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Quick Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Counting Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Radix Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Selection Sort")),
                      RaisedButton(onPressed: () {}, child: Text("Heap Sort")),
                    ],
                  ),
                ),
                Obx(
                  // rebuilds when observable variables change
                  () => Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [...controller.blockList],
                  ),
                ),
                // Row(
                //   children: [
                //     Container(
                //     child: Row(children: [
                //       Text("Algorithm")
                //     ],)
                //   )]
                // ),
              ],
            ),
          ),
        );
      }
    }
    

    这是您的Block,现在可以是无状态的。这里要注意的关键是更新颜色的GetBuilder 小部件。

    class Block extends StatelessWidget {
      // now can be stateless
      Block(this.height, this.width, this.mar);
      final double height;
      final double width;
      final double mar;
    
      @override
      Widget build(BuildContext context) {
        return (height == null)
            ? Container()
            : GetBuilder<BlockController>(
                // triggers rebuilds when update() is called from GetX class
                builder: (controller) => Container(
                  height: this.height,
                  width: width,
                  margin: EdgeInsets.all(mar),
                  decoration: BoxDecoration(
                    color: controller.color,
                  ),
                ),
              );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-01-01
      • 2021-07-20
      • 2019-12-17
      • 2022-11-12
      • 1970-01-01
      • 2021-09-11
      • 2021-08-17
      • 2021-06-11
      • 1970-01-01
      相关资源
      最近更新 更多