Flutter - 短暂状态管理
由于 Flutter 应用程序由 widget 组成,因此状态管理也由 widget 完成。状态管理的入口点是 Statefulwidget。Widget 可以从 Statefulwidget 继承,以维护其状态及其子状态。Statefulwidget 为 widget 提供了一个选项,当 widget 首次通过 createState 方法创建时,可以创建状态 State
让我们创建一个具有状态维护的 widget,RatingBox。该 widget 的目的是显示特定产品的当前评级。创建具有状态维护的 RatingBox 小部件的分步过程如下 −
通过继承 StatefulWidget 创建小部件 RatingBox。
class RatingBox extends StatefulWidget { }
通过继承 State<T> 为 RatingBox 创建状态 _RatingBoxState
class _RatingBoxState extends State<RatingBox> { }
重写 StatefulWidget 的 createState 方法以创建状态 _RatingBoxState。
class RatingBox extends StatefulWidget {
@override
_RatingBoxState createState() => _RatingBoxState();
}
在 _RatingBoxState 的 build 方法中创建 RatingBox 小部件的用户界面。通常,用户界面将在 RatingBox 小部件本身的 build 方法中完成。但是,当需要状态维护时,我们需要在 _RatingBoxState 小部件中构建用户界面。这可确保每当小部件的状态发生变化时重新呈现用户界面。
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
iconSize: _size,
),
), Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
iconSize: _size,
),
), Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
iconSize: _size,
),
),
],
);
}
在这里,我们使用了三颗星,使用 IconButton 小部件创建,并使用 Row 小部件将其排列在一行中。这个想法是通过红色星星的序列显示评级。例如,如果评级是两颗星,那么前两颗星将是红色的,最后一颗星是白色的。
在 _RatingBoxState 中编写方法来更改/设置小部件的状态。
void _setRatingAsOne() {
setState( () {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState( () {
_rating = 2;
});
}
void _setRatingAsThree() {
setState( () {
_rating = 3;
});
}
此处,每个方法都通过 setState 设置小部件的当前评级。
将用户手势(点击星星)连接到适当的状态更改方法。
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
此处,onPressed 事件调用相关函数来更改状态,随后更改用户界面。例如,如果用户点击第三颗星,则将调用 _setRatingAsThree 并将 _rating 更改为 3。由于状态已更改,因此将再次调用 build 方法并再次构建和渲染用户界面。
小部件 RatingBox 的完整代码如下 −
class RatingBox extends StatefulWidget {
@override
_RatingBoxState createState() => _RatingBoxState();
}
class _RatingBoxState extends State<RatingBox> {
int _rating = 0;
void _setRatingAsOne() {
setState( () {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState( () {
_rating = 2;
});
}
void _setRatingAsThree() {
setState( () {
_rating = 3;
});
}
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
让我们创建一个新的应用程序,并使用我们新创建的 RatingBox 小部件来显示产品的评级。
在 Android Studio 中创建一个新的 Flutter 应用程序 product_state_app。
用以下代码替换 main.dart 代码−
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 此小部件是您的应用程序的根。
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
), home: MyHomePage(title: 'Product state demo home page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: Text( 'Hello World', )
),
);
}
}
这里,
我们通过扩展 StatelessWidget 而不是默认的 StatefulWidget 创建了 MyHomePage 小部件,然后删除了相关代码。
包括我们新创建的 RatingBox 小部件。
创建一个 ProductBox 小部件以列出产品以及评级,如下所示 −
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.name, this.description, this.price, this.image})
: super(key: key);
final String name;
final String description;
final int price;
final String image;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 120,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.name, style: TextStyle(
fontWeight: FontWeight.bold)),
Text(this.description),
Text("Price: " + this.price.toString()),
RatingBox(),
],
)
)
)
]
)
)
);
}
}
更新 MyHomePage 小部件以包含下面指定的 ProductBox 小部件 −
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
ProductBox(
name: "Pixel",
description: "Pixel is the most feature phone ever",
price: 800,
image: "pixel.png"
),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"
),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for meeting",
price: 1500,
image: "tablet.png"
),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"
),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage medium",
price: 20,
image: "floppy.png"
),
],
)
);
}
}
该应用程序的完整代码如下 −
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 此小部件是您的应用程序的根。
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage( title: 'Product layout demo home page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"
),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"
),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for meeting",
price: 1500,
image: "tablet.png"
),
ProductBox(
name: "Pendrive",
description: "iPhone is the stylist phone ever",
price: 100,
image: "pendrive.png"
),
ProductBox(
name: "Floppy Drive",
description: "iPhone is the stylist phone ever",
price: 20,
image: "floppy.png"
),
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
],
)
);
}
}
class RatingBox extends StatefulWidget {
@override
_RatingBoxState createState() =>
_RatingBoxState();
}
class _RatingBoxState extends State<RatingBox> {
int _rating = 0;
void _setRatingAsOne() {
setState( () {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState( () {
_rating = 2;
});
}
void _setRatingAsThree() {
setState( () {
_rating = 3;
});
}
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.name, this.description, this.price, this.image}) :
super(key: key);
final String name;
final String description;
final int price;
final String image;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.name, style: TextStyle(fontWeight: FontWeight.bold)),
Text(this.description),
Text("Price: " + this.price.toString()),
RatingBox(),
],
)
)
)
]
)
)
);
}
}
-
最后运行应用,查看状态管理-商品列表页面结果如下图所示 −
点击评分星星会更新商品的评分,例如给 iPhone 设置 2 星评分,评分会显示如下图所示 −

flutter_state_management.html