65.9K
CodeProject 正在变化。 阅读更多。
Home

Flutter 入门:教程 2 – StateFulWidget

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2018年7月9日

CPOL

5分钟阅读

viewsIcon

19124

downloadIcon

206

让我们探讨 Flutter 中的 StateFulWidget 世界。

引言

在本文中,我将讨论Flutter中一个非常重要的概念,即StatefulWidget。如果您阅读了我第一篇文章,我创建的所有小部件在那里都是无状态的,根据Flutter网站的定义,小部件是不可变的,意味着它们的属性无法更改——所有值都是最终的,一旦显示。

那么,为什么我们要使用这种语言/框架,而又不能更改移动屏幕上的任何内容呢?答案在于Flutter开发人员卓越的架构方法StatefulWidget,它维护了在小部件生命周期中可能发生变化的state

背景

实现一个状态管理小部件至少需要两个类,它们是:

  1. 一个StatefulWidget类,它创建了一个State类的实例
  2. StatefulWidget类本身是不可变的,但是State类在小部件的生命周期内保持不变

我们将在本教程中进一步讨论这一点。

教程目标

我将创建一个小型移动应用程序,其中将包含以下内容:

  1. 显示应用程序名称的AppBar
  2. 用于接受用户输入的TextField
  3. 带有两个按钮的ButtonBar
    1. Clear 按钮:用于清除TextBox中的文本
    2. Add City 按钮:用于将用户输入添加到列表视图
  4. 用于持久化用户输入的ListView

总的来说,基本思想是创建一个应用程序中访问过的城市列表,这将展示StatefulWidget如何在小部件/类中的任何值发生变化时刷新屏幕。

Using the Code

那么,让我们直接深入应用程序,以下是如果您想动手实践的步骤:

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

  3. 现在,在lib文件夹下的main.dart文件中,删除所有内容并写入以下代码:
    import 'package:flutter/material.dart';
    import 'package:flutter2_sfw/widgets/mainpage.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @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'),
        );
      }
    }

    代码解释

    • 在这里,我们正在创建我们的主小部件,它将是我们移动应用程序的起点。
    • MyApp是一个StatelessWidget,它将作为第一页托管我们的StatefulWidget,这就是为什么我们传递MainPage(待创建)作为对象。

  4. 现在,右键单击lib文件夹,点击新建,然后添加一个名为widgets的包到文件夹。
  5. 添加一个名为mainpage.dart的新dart文件,其中将包含我们Stateful小部件的代码。
  6. StatefulStateless小部件之间的区别,对于创建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<MainPage> {
    
    @override
    Widget build(BuildContext context) {
      return new Scaffold(
          appBar: new AppBar(
            title: new Text(widget.title),
          ));
    }	

    代码解释

    • 在这里,我们创建MainPage类,它继承自StatefulWidget
    • 我们覆盖createState()函数,并为其提供链接的状态类。
    • _MainPageState类扩展了MainPage的通用状态,将包含构建UI的代码。
    • 如果我们此时运行我们的项目,在模拟器中就会看到以下视图:

  7. 现在是时候在上述步骤的scaffold的body中添加TextField和按钮了,build函数将如下所示:
    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: <Widget>[
                new TextField(
                  decoration: InputDecoration(
                    filled: true,
                    labelText: 'City Name',
                  ),
                  controller: _cityNameController,
                ),
                new ButtonBar(
                  children: <Widget>[
                    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<Widget> _lstText = new List<Widget>();

    _onAddCityBtnPressed() 函数

    当我们点击应用程序中的Add City 按钮时,将调用此函数。
    _onAddCityBtnPressed() {
      setState(() {
        _lstText
            .add(
            new Text("${_lstText.length + 1} ${_cityNameController.text}",
              textAlign: TextAlign.justify,
              style: new TextStyle(fontWeight:FontWeight.bold),));
        _cityNameController.clear();
      });

    代码解释

    • 在这里,我们创建了一个ListView控件,它是一个滚动控件,允许您放置可以垂直滚动的多个小部件。如果您现在不理解它,请不用担心,我将单独写一篇关于ListView的文章,讨论它提供的所有主要属性和方法。
    • 由于它可以接受多个子项,我们将添加的第一个子项将是TextField,这里我们有两个TextField的属性:
      • controller - 这将充当用于在屏幕上设置和获取值的对象。在这里,我们传递类成员_cityNameController。
      • decoration - 此属性将定义textfield的UI,我提供了labelText为'Add City',并将filled设置为true
    • 第二个子项是ButtonBar,它提供了添加多个按钮的模板,我创建了两个RaisedButton,第一个按钮将清除TextField的内容,另一个按钮将把TextField中存在的任何文本添加到名为_lstText的本地列表中。
      • Clear 按钮OnPressed将调用_cityNameController.clear();,这将清除textField控件。
      • Add City 按钮OnPressed将调用_onAddCityBtnPressed()方法,我将在下一步中说明其工作原理。
    • _onAddCityBtnPressed() - 将把TextField中的任何内容添加到_lstText中,并清除textField_lstText的类型是List,您可以从我的另一篇文章这里阅读更多关于它的信息。
    • 如果您没有注意到,当我们更新_lstText时,它被包装在setState()函数中,这是为了向框架指示某些对象已更新,您需要刷新状态。
  8. 现在是时候添加魔法了,直到完成第7点,我们才能够获取用户输入并将其存储在类变量中,然而屏幕上没有任何显示,即使在我们设置了状态并让框架知道我们更新了某些内容之后。现在是时候添加我们的ListView了,它会在_lstText更新时自动更新。我创建了两个函数来处理这种情况,在_MainPageState的build函数中添加getListViewBuilder()函数,并且我添加了这两个函数来创建ListView
    // Provide ListView from 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,
      );
    }
    
    // Call back function, will called for each item in the
    Widget getListItems(BuildContext context, int index) {
      return _lstText[index];
    }

    代码解释

    • 在这里,我们借助ListView.builder创建了一个ListView,通过传递itemCountitemBuilder属性的回调函数。
    • getListItems()函数将返回基于由回调函数传递给它的索引的小部件。
  9. 最终运行

至此,本文已接近尾声。请在留言板上告诉我您的评论。谢谢!

关注点

请阅读这些文章。它们可能会给您一个方向,告诉您真正的发展趋势。

  1. Flutter — 你可能喜欢它的 5 个理由
  2. Flutter 的革命性之处
  3. 为什么 Flutter 使用 Dart
  4. Github: https://github.com/thatsalok/FlutterExample/tree/master/flutter2_sfw

Flutter 教程

  1. Flutter 入门:教程 #1

Dart 教程

  1. DART2 Prima Plus - 教程 1
  2. DART2 Prima Plus - 第二课 - LIST

历史

  • 2018年7月9日:第一个版本
© . All rights reserved.