- Flutter 教程
- Flutter - 首页
- Flutter - 简介
- Flutter - 安装
- 在Android Studio中创建简单的应用程序
- Flutter - 架构应用程序
- Dart编程入门
- Flutter - Widget入门
- Flutter - 布局入门
- Flutter - 手势入门
- Flutter - 状态管理
- Flutter - 动画
- Flutter - 编写Android特定代码
- Flutter - 编写iOS特定代码
- Flutter - 包入门
- Flutter - 访问REST API
- Flutter - 数据库概念
- Flutter - 国际化
- Flutter - 测试
- Flutter - 部署
- Flutter - 开发工具
- Flutter - 编写高级应用程序
- Flutter - 结论
- Flutter 有用资源
- Flutter - 快速指南
- Flutter - 有用资源
- Flutter - 讨论
Flutter - 短暂状态管理
由于Flutter应用程序由Widget组成,因此状态管理也由Widget完成。状态管理的入口点是StatefulWidget。Widget可以继承自StatefulWidget来维护其状态及其子状态。StatefulWidget为Widget提供了一个选项,以便在Widget第一次通过createState方法创建时创建状态State
让我们创建一个具有状态维护的Widget,RatingBox。该Widget的目的是显示特定产品的当前评分。创建具有状态维护的RatingBox Widget的分步过程如下:
通过继承StatefulWidget创建Widget 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 Widget的用户界面。通常,用户界面将在RatingBox Widget本身的build方法中完成。但是,当需要状态维护时,我们需要在_RatingBoxState Widget中构建用户界面。这确保了每当Widget的状态发生更改时,用户界面都会重新渲染。
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 Widget创建,并使用Row Widget将其排列在同一行中。其思想是通过红色星形的序列显示评分。例如,如果评分为两星,则前两颗星将为红色,最后一颗为白色。
在_RatingBoxState中编写方法来更改/设置Widget的状态。
void _setRatingAsOne() { setState( () { _rating = 1; }); } void _setRatingAsTwo() { setState( () { _rating = 2; }); } void _setRatingAsThree() { setState( () { _rating = 3; }); }
在这里,每个方法都通过setState设置Widget的当前评分。
将用户手势(点击星形)连接到适当的状态更改方法。
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方法,并且将再次构建和渲染用户界面。
Widget 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 Widget来显示产品的评分。
在Android Studio中创建一个新的Flutter应用程序,product_state_app。
将main.dart代码替换为以下代码:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @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 Widget,然后删除了相关代码。
包含我们新创建的RatingBox Widget。
创建一个ProductBox Widget来列出产品及其评分,如下所示:
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 Widget以包含ProductBox Widget,如下所示:
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 { // This widget is the root of your application. @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星评级将显示如下评分: