在flutter中从另一个小部件更新小部件的状态

时间:2021-03-25 17:22:33

标签: flutter dart state-management

我一直在用 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,
            ),
          );
  }
}

1 个答案:

答案 0 :(得分: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());

现在所有这些逻辑都隐藏在 GetX 类中,这让您的工作少了很多 DashBoard。在这里我们找到控制器,并使用它访问所有这些变量和方法。

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

enter image description here