Flutter中的StateFulWidget概念

Flutter框架中,StateFulWidget是一个非常重要的概念。StateFulWidget允许开发者创建可以改变状态的widget,这在构建动态用户界面时非常有用。与StatelessWidget不同,StatelessWidget的属性是不可变的,一旦显示在屏幕上就不能更改。StateFulWidget通过State类来维护可能在widget生命周期内发生变化的状态。

本教程的目标是创建一个简单的移动应用程序,该程序包含以下功能:

  • AppBar:显示应用程序名称
  • TextField:接受用户输入
  • ButtonBar:包含两个按钮
  • 清除按钮:清除文本框中的文本
  • 添加城市按钮:将用户输入添加到列表视图
  • ListView:持久化用户输入

通过这个应用程序,将展示StateFulWidget如何在widget或类/属性的值发生变化时刷新屏幕。

使用代码

让直接进入应用程序的创建步骤:

  1. 打开Android Studio并创建一个新的Flutter项目,命名为flutter2_sfw(StateFulWidget的简称)。如果使用Visual Studio Code,请在终端窗口中使用命令flutter create flutter2_sfw。请确保Flutter的bin路径已添加到环境变量中。
  2. 项目创建完成后,基本结构如下:

main.dart文件中,删除所有内容并编写以下代码:

import 'package:flutter/material.dart'; import 'package:flutter2_sfw/widgets/mainpage.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { // 这个widget是应用程序的根。 @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.amber, ), home: new MainPage(title: 'Flutter 2 - Add City'), ); } }

在这里,创建了主widget,它将是移动应用程序的起点。MyApp是StatelessWidget,它将托管StateFulWidget作为第一页,这就是为什么传递MainPage(待创建)作为对象的原因。

接下来,在lib文件夹中右键单击并选择新建,然后添加一个名为widgets的包。在其中添加一个新的dart文件,命名为mainpage.dart,它将包含StateFul widget的代码。

StateFul和Stateless widget的区别在于,创建StateFulWidget至少需要两个类:一个是实际的页面,另一个是持有页面状态的类。

class MainPage extends StatefulWidget { MainPage({Key key, this.title}) : super(key: key); final String title; @override _MainPageState createState() => new _MainPageState(); } class _MainPageState extends State { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), ); } }

在这里,创建了MainPage类,它继承自StateFulWidget。重写了createState()函数,并提供了与之关联的状态类_MainPageState,它扩展了MainPage的泛型状态,将包含构建UI的代码。

如果在这一点上运行项目,这将是模拟器中的视图:

现在是时候在上述步骤的Scaffold主体中添加TextField和按钮了,构建函数将如下所示:

Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new ListView( padding: const EdgeInsets.symmetric(horizontal: 5.0), children: [ new TextField( decoration: InputDecoration( filled: true, labelText: 'City Name', ), controller: _cityNameController, ), new ButtonBar( children: [ new RaisedButton( onPressed: () { _cityNameController.clear(); }, child: new Text('Clear'), ), new RaisedButton( child: new Text('Add City'), onPressed: _onAddCityBtnPressed, color: Colors.amber, ) ], ), ], ), ); }

新类成员(_MainPageState):

final TextEditingController _cityNameController = TextEditingController(); final List _lstText = new List(); _onAddCityBtnPressed() Function

这个函数将在按下应用程序中的“添加城市”按钮时被调用。

_onAddCityBtnPressed() { setState(() { _lstText.add(new Text( "${_lstText.length + 1} ${_cityNameController.text}", textAlign: TextAlign.justify, style: new TextStyle(fontWeight: FontWeight.bold), )); _cityNameController.clear(); }); }

在这里,创建了一个ListView控件,它是一个滚动控件,允许放置可以垂直滚动的多个widget。不用担心,如果现在不理解,将为ListView编写另一篇文章,讨论它提供的所有突出属性和方法。

由于它可以容纳多个子项,首先添加的子项将是TextField,在这里有两个TextField属性:

  • controller - 这将充当从屏幕上设置和获取值的对象。在这里,传递了类成员_cityNameController。
  • decoration - 这个属性将定义textfield的UI,提供了labelText,即'Add City',以及filled为true。

第二个子项是ButtonBar,它提供了添加多个按钮的模板,创建了两个RaisedButton,第一个将清除TextField的内容,另一个按钮将把TextField中的任何文本添加到名为_lstText的本地列表中。

  • 清除按钮:OnPressed将调用_cityNameController.clear(),它将清除textField控件。
  • 添加城市按钮:OnPressed将调用_onAddCityBtnPressed()方法,其工作原理将在下一步中说明。

_onAddCityBtnPressed() - 将把TextField中的内容添加到_lstText中,并清除textField。_lstText是List类型,可以从另一篇文章中了解更多信息。

如果没有注意到,当更新_lstText时,它被包裹在setState()函数中,它在那里是为了指示框架,一些对象已更新,需要刷新状态。

现在是时候添加魔法了,直到第7点,能够接受用户输入并将其存储在类变量中,但是即使设置了状态并使框架意识到更新了某些内容,屏幕上仍然没有任何显示。现在是时候添加ListView了,它将在_lstText更新时更新自己。在_MainPageState的构建函数中创建了两个函数来处理这种情况,添加getListViewBuilder()函数,并为创建ListView添加了这两个函数:

// 提供ListView从ListView.builder ListView getListViewBuilder() { return new ListView.builder( shrinkWrap: true, itemCount: _lstText.length, padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0), itemBuilder: getListItems, ); } // 回调函数,将为每个项目调用 Widget getListItems(BuildContext context, int index) { return _lstText[index]; }

在这里,使用ListView.builder创建了ListView,传递了itemCount和itemBuilder属性的回调函数。getListItems()函数将根据回调函数传递给它的索引返回widget。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485