Flutter 中的 setState() 方法直到 for 循环中的最后一次调用才更新视图
setState() method in Flutter is not updating the view until the last call in a for loop
问题
我正在尝试使用 Flutter 构建一个排序可视化工具。我已经使用 CustomPainter
绘制与我打算排序的整数列表的值相对应的垂直线。
该应用程序设置为当用户单击 DropDownButton
中的 "Bubble sort" 选项时
(我打算稍后添加更多排序算法)CustomPainter
中的垂直线 Canvas 必须自行排序。
代码
import 'dart:io';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() => runApp(HomePage());
class HomePage extends StatefulWidget {
@override
HomePageSate createState() {
return HomePageState();
}
}
class HomePageState extends State<HomePage> {
List<int> arr;
@override
void initState() {
super.initState();
arr = _getRandomIntegerList();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Sorting Visualiser'),
actions: <Widget>[
DropdownButton<String>(
onChanged: (dynamic choice) {
switch (choice) {
case 'Bubble Sort':
_bubbleSortVisualiser();
break;
}
},
items: <String>['Bubble Sort']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
],
),
//The following flatButton refreshes arr to have a new array of random integers.
bottomNavigationBar: FlatButton(
onPressed: () {
setState(() {
arr = _getRandomIntegerList();
});
},
child: Icon(Icons.refresh),
),
body: CustomPaint(
size: Size(double.infinity, double.infinity),
painter: SortingCanvas(arr),
),
),
);
}
//function to sort the list using bubble sort and repaint the canvas at every iteration.
void _bubbleSortVisualiser() {
print('Bubble sort function called');
List<int> bubbleArr = List.from(arr);
for (int i = 0; i < bubbleArr.length - 1; i++) {
for (int j = 0; j < bubbleArr.length - 1 - i; j++) {
int temp;
if (bubbleArr[j] < bubbleArr[j + 1]) {
temp = bubbleArr[j];
bubbleArr[j] = bubbleArr[j + 1];
bubbleArr[j + 1] = temp;
//Every time arr changes setState() is called to visualise the changing array.
setState(() {
arr = List.from(bubbleArr);
print("Updated to : $arr");
});
//Sleep is called so that the change is noticeable
sleep(Duration(seconds: 1));
}
}
}
}
}
class SortingCanvas extends CustomPainter {
List<int> arr;
SortingCanvas(this.arr);
@override
void paint(Canvas canvas, Size size) {
var linePaint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 5.0
..isAntiAlias = true;
//IMP the first offset is the bottom point and the second is the top point of the vertical line.
//It is offset from the top left corner of the canvas
for (int i = 1; i <= arr.length; i++) {
canvas.drawLine(Offset(50.0 + (20 * i), size.height - 50),
Offset(50.0 + (20 * i), 50.0 * arr[i - 1]), linePaint);
}
}
@override
bool shouldRepaint(SortingCanvas oldDelegate) {
return !listEquals(this.arr, oldDelegate.arr);
}
}
//Helper function to get a list of 10 random integers
List<int> _getRandomIntegerList() {
List<int> arr = [];
Random rng = new Random();
for (int i = 0; i < 10; i++) {
arr.add(rng.nextInt(10));
}
return arr;
}
然而,最终发生的是只有最终排序的 arr
在 canvas 上可视化并且由于某种原因跳过了所有中间步骤。但是日志显示列表正在更新。
截图
带有随机列表的初始屏幕
点击下拉按钮中的冒泡排序
排序后的列表
添加 sleep()
功能只是为了模拟动画,我打算在解决此问题后将其替换为适当的动画。另外,我知道该应用程序有点难看,但我想在任何 UI 润色之前弄清楚逻辑。
这一行:
class HomePageState extends State<StatefulWidget> {
应该是
class HomePageState extends State<HomePage> {
就是这样。那么它应该可以工作了。
另外,你应该改变这个:
@override
State<StatefulWidget> createState() {
return HomePageState();
}
至:
@override
State<HomePage> createState() => HomePageState();
尝试使用Future.delay喜欢
void _bubbleSortVisualiser() async {
print('Bubble sort function called');
List<int> bubbleArr = List.from(arr);
for (int i = 0; i < bubbleArr.length - 1; i++) {
for (int j = 0; j < bubbleArr.length - 1 - i; j++) {
int temp;
if (bubbleArr[j] < bubbleArr[j + 1]) {
temp = bubbleArr[j];
bubbleArr[j] = bubbleArr[j + 1];
bubbleArr[j + 1] = temp;
//Every time arr changes setState() is called to visualise the changing array.
await Future.delayed(const Duration(seconds: 1), () {
setState(() {
arr = List.from(bubbleArr);
print("Updated to : $arr");
});
});
}
}
}
}
}
问题
我正在尝试使用 Flutter 构建一个排序可视化工具。我已经使用 CustomPainter
绘制与我打算排序的整数列表的值相对应的垂直线。
该应用程序设置为当用户单击 DropDownButton
中的 "Bubble sort" 选项时
(我打算稍后添加更多排序算法)CustomPainter
中的垂直线 Canvas 必须自行排序。
代码
import 'dart:io';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() => runApp(HomePage());
class HomePage extends StatefulWidget {
@override
HomePageSate createState() {
return HomePageState();
}
}
class HomePageState extends State<HomePage> {
List<int> arr;
@override
void initState() {
super.initState();
arr = _getRandomIntegerList();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Sorting Visualiser'),
actions: <Widget>[
DropdownButton<String>(
onChanged: (dynamic choice) {
switch (choice) {
case 'Bubble Sort':
_bubbleSortVisualiser();
break;
}
},
items: <String>['Bubble Sort']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
],
),
//The following flatButton refreshes arr to have a new array of random integers.
bottomNavigationBar: FlatButton(
onPressed: () {
setState(() {
arr = _getRandomIntegerList();
});
},
child: Icon(Icons.refresh),
),
body: CustomPaint(
size: Size(double.infinity, double.infinity),
painter: SortingCanvas(arr),
),
),
);
}
//function to sort the list using bubble sort and repaint the canvas at every iteration.
void _bubbleSortVisualiser() {
print('Bubble sort function called');
List<int> bubbleArr = List.from(arr);
for (int i = 0; i < bubbleArr.length - 1; i++) {
for (int j = 0; j < bubbleArr.length - 1 - i; j++) {
int temp;
if (bubbleArr[j] < bubbleArr[j + 1]) {
temp = bubbleArr[j];
bubbleArr[j] = bubbleArr[j + 1];
bubbleArr[j + 1] = temp;
//Every time arr changes setState() is called to visualise the changing array.
setState(() {
arr = List.from(bubbleArr);
print("Updated to : $arr");
});
//Sleep is called so that the change is noticeable
sleep(Duration(seconds: 1));
}
}
}
}
}
class SortingCanvas extends CustomPainter {
List<int> arr;
SortingCanvas(this.arr);
@override
void paint(Canvas canvas, Size size) {
var linePaint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 5.0
..isAntiAlias = true;
//IMP the first offset is the bottom point and the second is the top point of the vertical line.
//It is offset from the top left corner of the canvas
for (int i = 1; i <= arr.length; i++) {
canvas.drawLine(Offset(50.0 + (20 * i), size.height - 50),
Offset(50.0 + (20 * i), 50.0 * arr[i - 1]), linePaint);
}
}
@override
bool shouldRepaint(SortingCanvas oldDelegate) {
return !listEquals(this.arr, oldDelegate.arr);
}
}
//Helper function to get a list of 10 random integers
List<int> _getRandomIntegerList() {
List<int> arr = [];
Random rng = new Random();
for (int i = 0; i < 10; i++) {
arr.add(rng.nextInt(10));
}
return arr;
}
然而,最终发生的是只有最终排序的 arr
在 canvas 上可视化并且由于某种原因跳过了所有中间步骤。但是日志显示列表正在更新。
截图
带有随机列表的初始屏幕
添加 sleep()
功能只是为了模拟动画,我打算在解决此问题后将其替换为适当的动画。另外,我知道该应用程序有点难看,但我想在任何 UI 润色之前弄清楚逻辑。
这一行:
class HomePageState extends State<StatefulWidget> {
应该是
class HomePageState extends State<HomePage> {
就是这样。那么它应该可以工作了。
另外,你应该改变这个:
@override
State<StatefulWidget> createState() {
return HomePageState();
}
至:
@override
State<HomePage> createState() => HomePageState();
尝试使用Future.delay喜欢
void _bubbleSortVisualiser() async {
print('Bubble sort function called');
List<int> bubbleArr = List.from(arr);
for (int i = 0; i < bubbleArr.length - 1; i++) {
for (int j = 0; j < bubbleArr.length - 1 - i; j++) {
int temp;
if (bubbleArr[j] < bubbleArr[j + 1]) {
temp = bubbleArr[j];
bubbleArr[j] = bubbleArr[j + 1];
bubbleArr[j + 1] = temp;
//Every time arr changes setState() is called to visualise the changing array.
await Future.delayed(const Duration(seconds: 1), () {
setState(() {
arr = List.from(bubbleArr);
print("Updated to : $arr");
});
});
}
}
}
}
}