- 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 通过 StatefulWidget 支持它。
应用程序状态 − 持续整个应用程序,例如已登录用户详细信息、购物车信息等。Flutter 通过 scoped_model 支持它。
导航和路由
在任何应用程序中,从一个页面/屏幕导航到另一个页面/屏幕都定义了应用程序的工作流程。处理应用程序导航的方式称为路由。Flutter 提供了一个基本的路由类 – MaterialPageRoute 和两种方法 - Navigator.push 和 Navigator.pop,用于定义应用程序的工作流程。
MaterialPageRoute
MaterialPageRoute 是一个 widget,用于通过使用特定于平台的动画替换整个屏幕来渲染其 UI。
MaterialPageRoute(builder: (context) => Widget())
在这里,builder 将接受一个函数,通过提供应用程序的当前上下文来构建其内容。
Navigation.push
Navigation.push 用于使用 MaterialPageRoute widget 导航到新屏幕。
Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );
Navigation.pop
Navigation.pop 用于导航到上一屏幕。
Navigator.push(context);
让我们创建一个新的应用程序来更好地理解导航概念。
在 Android studio 中创建一个新的 Flutter 应用程序,product_nav_app
将 assets 文件夹从 product_nav_app 复制到 product_state_app,并在 pubspec.yaml 文件中添加 assets。
flutter: assets: - assets/appimages/floppy.png - assets/appimages/iphone.png - assets/appimages/laptop.png - assets/appimages/pendrive.png - assets/appimages/pixel.png - assets/appimages/tablet.png
将默认启动代码 (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',) ), ); } }
让我们创建一个 Product 类来组织产品信息。
class Product { final String name; final String description; final int price; final String image; Product(this.name, this.description, this.price, this.image); }
让我们在 Product 类中编写一个 getProducts 方法来生成我们的虚拟产品记录。
static List<Product> getProducts() { List<Product> items = <Product>[]; items.add( Product( "Pixel", "Pixel is the most feature-full phone ever", 800, "pixel.png" ) ); items.add( Product( "Laptop", "Laptop is most productive development tool", 2000, " laptop.png" ) ); items.add( Product( "Tablet", "Tablet is the most useful device ever for meeting", 1500, "tablet.png" ) ); items.add( Product( "Pendrive", "Pendrive is useful storage medium", 100, "pendrive.png" ) ); items.add( Product( "Floppy Drive", "Floppy drive is useful rescue storage medium", 20, "floppy.png" ) ); return items; } import product.dart in main.dart import 'Product.dart';
让我们包含我们的新 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, ), ), ], ); } }
让我们修改我们的 ProductBox widget 以与我们的新 Product 类一起工作。
class ProductBox extends StatelessWidget { ProductBox({Key key, this.item}) : super(key: key); final Product item; 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/" + this.item.image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), Text("Price: " + this.item.price.toString()), RatingBox(), ], ) ) ) ] ), ) ); } }
让我们重写我们的 MyHomePage widget 以使用 Product 模型并使用 ListView 列出所有产品。
class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; final items = Product.getProducts(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Product Navigation")), body: ListView.builder( itemCount: items.length, itemBuilder: (context, index) { return GestureDetector( child: ProductBox(item: items[index]), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ProductPage(item: items[index]), ), ); }, ); }, )); } }
在这里,我们使用了 MaterialPageRoute 导航到产品详情页面。
现在,让我们添加 ProductPage 来显示产品详情。
class ProductPage extends StatelessWidget { ProductPage({Key key, this.item}) : super(key: key); final Product item; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.item.name), ), body: Center( child: Container( padding: EdgeInsets.all(0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Image.asset("assets/appimages/" + this.item.image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text( this.item.name, style: TextStyle( fontWeight: FontWeight.bold ) ), Text(this.item.description), Text("Price: " + this.item.price.toString()), RatingBox(), ], ) ) ) ] ), ), ), ); } }
应用程序的完整代码如下:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class Product { final String name; final String description; final int price; final String image; Product(this.name, this.description, this.price, this.image); static List<Product> getProducts() { List<Product> items = <Product>[]; items.add( Product( "Pixel", "Pixel is the most featureful phone ever", 800, "pixel.png" ) ); items.add( Product( "Laptop", "Laptop is most productive development tool", 2000, "laptop.png" ) ); items.add( Product( "Tablet", "Tablet is the most useful device ever for meeting", 1500, "tablet.png" ) ); items.add( Product( "Pendrive", "iPhone is the stylist phone ever", 100, "pendrive.png" ) ); items.add( Product( "Floppy Drive", "iPhone is the stylist phone ever", 20, "floppy.png" ) ); items.add( Product( "iPhone", "iPhone is the stylist phone ever", 1000, "iphone.png" ) ); return items; } } 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 Navigation demo home page'), ); } } class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; final items = Product.getProducts(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Product Navigation")), body: ListView.builder( itemCount: items.length, itemBuilder: (context, index) { return GestureDetector( child: ProductBox(item: items[index]), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ProductPage(item: items[index]), ), ); }, ); }, ) ); } } class ProductPage extends StatelessWidget { ProductPage({Key key, this.item}) : super(key: key); final Product item; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.item.name), ), body: Center( child: Container( padding: EdgeInsets.all(0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Image.asset("assets/appimages/" + this.item.image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), Text("Price: " + this.item.price.toString()), 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, ), ), ], ); } } class ProductBox extends StatelessWidget { ProductBox({Key key, this.item}) : super(key: key); final Product item; 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/" + this.item.image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), Text("Price: " + this.item.price.toString()), RatingBox(), ], ) ) ) ] ), ) ); } }
运行应用程序并点击任何一个产品项目。它将显示相关的详细信息页面。我们可以通过点击后退按钮返回主页。应用程序的产品列表页面和产品详情页面如下所示: