关于重新渲染,我似乎“失去了泡沫”!我不确定我的应用的当前实现有什么问题。它是在许多SO成员的帮助下派生的。
应该做的:渲染9个绿色的圆圈,然后一个接一个地以递增或递减的顺序将每个圆圈呈现为黄色(“圆圈”小部件)。显示计数的当前值(“计数器”小部件)。在AppBar(“主页”页面小部件)中:识别+的抽头和递增计数,识别-的抽头和递减计数。在这两种情况下,都要在setState方法的主体中执行递增/递减操作。 “圆”和“计数器”小部件都有望重新渲染。在此实现中,所有圈子都参与了从绿色到黄色到绿色的颜色更改(有效计数被忽略了)。
它的作用:根据需要显示“圆”和“计数器”小部件的初始渲染。但是,尽管可以识别AppBar图标(+和-),但不会导致Circles小部件的重新渲染。计数器小部件确实重新渲染其计数显示。在“圆圈”小部件中有一个RaisedButton,当点击该按钮时,会引起“圆圈”小部件的重新渲染。但是该按钮在最终实现中是不需要的,仅用于测试。
让我感到困惑的是,“圈子”窗口小部件使用的模板与“计数器”窗口小部件使用的模板相同。但是它们的执行方式似乎有所不同。
整个应用程序的源代码如下。它是一个.dart文件(很长,很抱歉,但是过去遗漏了一些问题)。
有想法吗?
// ignore_for_file: camel_case_types
// ignore_for_file: constant_identifier_names
// ignore_for_file: non_constant_identifier_names
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:math';
const int NUMBER_TILES = 9;
final int CROSS_AXIS_COUNT = (sqrt(NUMBER_TILES)).toInt();
const double CROSS_AXIS_SPACING = 4.0;
const int INITIAL_COUNT = 9; // for testing; should be 1
const double MAIN_AXIS_SPACING = CROSS_AXIS_SPACING;
const int MILLISECOND_MULTIPLIER = 500;
// ************************************************************** main
void main() {
final AppState app_state = new AppState(counter: INITIAL_COUNT);
runApp(new Home_Page(app_state: app_state));
} // main
// **************************************************** class AppState
class AppState {
int counter = 0;
List<int> flash_indices = [];
bool forward = false;
AppState({this.counter}); // AppState
String toString() { // toString
return ( 'AppState{' +
'counter: $counter, ' +
'flash_indices: $flash_indices}');
} // toString
// following is a mock
void randomize_flash_indices ( ) { // randomize_flash_indices
forward = !forward;
if ( forward){
flash_indices = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, -1];
}
else {
flash_indices = [ 8, 7, 6, 5, 4, 3, 2, 1, 0, -1];
}
flash_indices.add (-1); // restore to normal colors
} // randomize_flash_indices
} // class AppState
// *************************************************** class Home_Page
class Home_Page
extends StatefulWidget {
final AppState app_state;
Home_Page({
@required this.app_state,
Key key,
}) : super(key: key);
@override
State<StatefulWidget> createState() {
return Home_Page_State();
}
} // class Home_Page
// ********************************************* class Home_Page_State
class Home_Page_State extends State<Home_Page>{
Home_Page_State();
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Periodic',
theme: new ThemeData(primarySwatch: Colors.indigo),
home: Scaffold(
appBar: AppBar(
title: Text('Periodic'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add), // increment counter
onPressed: () {
if (widget.app_state.counter < NUMBER_TILES){
setState(() {
widget.app_state.counter++;
});
}
}
),
IconButton(
icon: Icon(Icons.remove), // decrement counter
onPressed: () {
if (widget.app_state.counter > 1){
setState(() {
widget.app_state.counter--;
});
}
}
),
]
),
body: Column(
children: [
Circles (
app_state: widget.app_state,
),
Counter (
app_state: widget.app_state,
)
],
),
),
);
} // Home_Page_State build
} // class Home_Page_State
// ***************************************************** class Circles
class Circles extends StatefulWidget {
final AppState app_state;
Circles({
@required this.app_state,
Key key,
}) : super(key: key);
@override
State<StatefulWidget> createState() {
return Circles_State();
}
} // class Circles
// *********************************************** class Circles_State
class Circles_State extends State<Circles>{
Circles_State();
int flash_tile = -1;
List<GridTile> grid_tiles = <GridTile>[];
StreamController<int> tick_controller;
StreamSubscription<int> tick_listener;
Stream<int> start_ticking() { // start_ticking
tick_controller = new StreamController();
for ( int tick = 0; (tick < widget.app_state.counter); tick++ ) {
Future.delayed(Duration(milliseconds:
MILLISECOND_MULTIPLIER * tick),() {
print('start_ticking() tick: $tick');
tick_controller.add(tick);
});
}
return tick_controller.stream;
} // start_ticking
@override
void initState() { // initState
super.initState();
widget.app_state.randomize_flash_indices();
tick_listener = start_ticking().listen(on_tick);
} // initState
@override
void dispose() { // dispose
if (tick_listener != null) {
tick_listener.cancel();
tick_listener = null;
}
super.dispose();
} // dispose
on_tick(int tick) async { // on_tick
print('listen_for_tick() tick: $tick');
this.setState(() => this.flash_tile =
widget.app_state.
flash_indices[tick]);
} // on_tick
GridTile new_circle_tile( // new_circle_tile
Color tile_color,
int index) {
GridTile tile = GridTile(
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
color: tile_color,
shape: BoxShape.circle,
),
),
)
);
return (tile);
} // new_circle_tile
List<GridTile> create_circle_tiles() {// create_circle_tiles
grid_tiles = new List<GridTile>();
for (int i = 0; (i < NUMBER_TILES); i++) {
Color tile_color =
( this.flash_tile == i) ?
Colors.yellow :
Colors.green;
grid_tiles.add(new_circle_tile(tile_color, i));
}
return (grid_tiles);
} // create_circle_tiles
@override // Circles_State
Widget build(BuildContext context) {
print('Circles_State Build ' +
widget.app_state.toString() +
' flash_tile: $flash_tile');
return Column(
children: [
GridView.count(
shrinkWrap: true,
crossAxisCount: CROSS_AXIS_COUNT,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
children: create_circle_tiles(),
),
RaisedButton(
child: Text("restart"),
onPressed: () {
widget.app_state.randomize_flash_indices();
tick_listener = start_ticking().listen(on_tick);
}
),
] // children
);
} // Circles_State build
} // class Circles_State
// ***************************************************** class Counter
class Counter extends StatefulWidget {
final AppState app_state;
Counter({
@required this.app_state,
Key key,
}) : super(key: key);
@override
State<StatefulWidget> createState() {
return Counter_State();
}
} // class Counter
// *********************************************** class Counter_State
class Counter_State extends State<Counter> {
Counter_State();
@override // Counter_State
Widget build(BuildContext context) {
int counter_value = widget.app_state.counter;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: SizedBox(
width: 24.0,
child: Center(
child: Text(
'Counter $counter_value',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
),
),
),
),
],
);
} // Counter_State build
} // class Counter_State
答案 0 :(得分:0)
我对找到的解决方案感到非常失望-将所有小部件组合到一个类中。原始架构的骨架看起来像:
void main(){
:
} // main()
class AppState {
:
} // class AppState
class HomePage extends StatefulWidget {
:
} // class HomePage
class HomePageState extends State<HomePage>{
:
} // class HomePageState
class Circles extends StatefulWidget {
:
} // class Circles
class CirclesState extends State<Circles>{}
:
} // class CirclesState
class Counter extends StatefulWidget {
:
} // class Counter
class CounterState extends State<Counter>{}
:
} // class CounterState
每个类都可以放入其自己的 .dart 文件中。但是,为了获得所需的结果,我必须消除除 HomePage 和 HomePageState 之外的所有类。所有其他类(变量,方法和函数)的内容都必须放入 HomePageState 中,以便在状态更改时,小部件可以正确更新。修改后的实现的框架如下:
void main(){
:
} // main()
class HomePage extends StatefulWidget {
:
} // class HomePage
class HomePageState extends State<HomePage>{
:
void randomize_flash_indices ( ) {...
Stream<int> start_ticking() { ...
@override
void initState() { ...
@override
void dispose() { ...
on_tick(int tick) async { ...
Circles(){ ...
Counter(){ ...
@override
Widget build(BuildContext context) {...
:
} // class HomePageState
此实现是整体的,并且面对良好的编程(和设计)(和体系结构)原则。这种软件无法在生产环境中维护。
似乎Dart语言的设计师错过了关于setState()的要点,或者我完全错过了正确的编码实践。因为我是一位经验丰富的程序员(超过42年),所以我常常会怀疑后者(当然,因为,我是一位经验丰富的程序员,所以我意识到我可能缺少关于setState的重要知识)。
我对扑扑/飞镖感到失望。我曾希望Xamarin有所帮助-我猜我不会从扑打/飞镖中得到它。