zoukankan      html  css  js  c++  java
  • Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget

    前言

    上一篇我们对 Flutter UI 有了一个基本的了解。

    这一篇我们通过自定义 Widget 来了解下如何写一个 Widget?

    然而 Widget 有两个,StatelessWidget 和 StatefulWidget,我们要继承哪一个?

    下面让我们跟着文章来探索一番。

    目录

    1. StatelessWidget

    我们先来看下继承的 Widget 为 StatelessWidget 的情况。

    第一步:新建一个文件 bold_text.dart

    这里文件名后面后缀 .dart 可带可不带

    这里文件名后面后缀 .dart 可带可不带

    文件名多个单词组成用下划线分隔。

    这里我们演示直接在 lib 文件夹下面创建,实际项目记得文件夹结构的组织哦~

    第二步:import 系统包

    一般自定义 Widget 都要 import 下面的一个包。

    import 'package:flutter/material.dart';
    

    IDE 有自动提示和补全功能,因此不用死记硬背。

    第三步:自定义一个类继承自 StatelessWidget

    一般类名跟文件名一致就可以,采用驼峰格式命名。

    import 'package:flutter/material.dart';
    
    class BoldText extends StatelessWidget {
      
    }
    

    第四步:实现一个需要 override 的方法 build

    import 'package:flutter/material.dart';
    
    class BoldText extends StatelessWidget {
      
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return null;
      }
    
    }
    

    一般第三步操作之后 IDE 有提示,直接使用快捷修复自动追加 build 代码即可。如下图:

    第五步:实现 Widget

    上述代码的 TODO 表示我们要在里面实现对应的 Widget。所以我们删除 TODO,然后在写我们要返回的 Widget 来替换 null 即可。

    我们写一个单独的方法 _buildWidget 来返回 Widget,同时返回我们之前写的 Text,如下:

    import 'package:flutter/material.dart';
    
    class BoldText extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return _buildWidget();
      }
    
      Widget _buildWidget() {
        return Text(
          'Hello, world!',
          textDirection: TextDirection.ltr,
          textAlign: TextAlign.center,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(fontWeight: FontWeight.bold),
        );
      }
    
    }
    

    可以看到我们这个 Widget 应该会显示成上篇我们界面所见的粗体文本。

    但是这里 Hello, world! 写死了,我们要让这个自定义 Widget 通用一些,可以定义一个必传参数文本内容,修改如下:

    import 'package:flutter/material.dart';
    
    class BoldText extends StatelessWidget {
    
      final String data;
    
      BoldText(this.data);
    
      @override
      Widget build(BuildContext context) {
        return _buildWidget();
      }
    
      Widget _buildWidget() {
        return Text(
          data,
          textDirection: TextDirection.ltr,
          textAlign: TextAlign.center,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(fontWeight: FontWeight.bold),
        );
      }
    
    }
    

    可以看到我们定义了一个变量,通过构造函数让外部传进来。

    这里的 BoldText(this.data); 等价于 Android 下面代码:

        BoldText(String data) {
            this.data = data;
        }
    

    可以看到 dart 的语法糖简化了写法。具体更多构造函数写法可以查看 dart 官网

    2. 自定义 Widget 使用

    我们以之前的 main.dart 为例进行讲解。

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text(
            'Hello, world!',
            textDirection: TextDirection.ltr,
            textAlign: TextAlign.center,
            overflow: TextOverflow.ellipsis,
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
        );
      }
    }
    

    第一步:导入我们的自定义 Widget 包

    相对路径:

    import 'bold_text.dart';
    

    绝对路径:

    import 'package:my_flutter/bold_text.dart';
    

    上面任选其一即可。主要是相对路径和绝对路径的区别。

    第二步:使用

    import 'package:flutter/material.dart';
    
    import 'bold_text.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: BoldText('Hello, world!'),
        );
      }
    }
    

    对比可以看到节省了很多代码行,尤其对于有多个地方用到的公共组件更加可以这样处理。

    3. StatelessWidget 通用模板

    FileName为你文件名的驼峰形式:

    import 'package:flutter/material.dart';
    
    class FileName extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return _buildWidget();
      }
    
      Widget _buildWidget() {
        //TODO build your widget
      }
    
    }
    

    4. StatefulWidget

    我们再来看下继承的 Widget 为 StatefulWidget 的情况。

    第一步:新建 increment.dart 文件

    第二步:import 系统包

    第三步:自定义一个类继承自 StatefulWidget

    第四步:实现一个需要 override 的方法 createState

    到这里就有点不一样了。我们先看下目前的代码。

    import 'package:flutter/material.dart';
    
    class Increment extends StatefulWidget{
    
      @override
      State<StatefulWidget> createState() {
        // TODO: implement createState
        return null;
      }
    
    }
    

    和 StatelessWidget 不一样,这里不是返回 Widget。

    我们看下如何操作。

    第五步:创建一个类继承 State< T extends StatefulWidget>

    这里我们创建 _IncrementState 类继承 State< Increment>,这里尖括号<>里面的类型就是我们一开始写的继承自 StatefulWidget 的类 Increment。

    然后我们需要实现一个需要 override 的方法 build。

    到这里是不是就是很熟悉了。

    直接看代码:

    import 'package:flutter/material.dart';
    
    class Increment extends StatefulWidget{
    
      @override
      State<StatefulWidget> createState() {
        return _IncrementState();
      }
    
    }
    
    class _IncrementState extends State<Increment> {
    
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return null;
      }
    
    }
    

    所以接下来的工作就是类似的。

    第六步:实现 Widget

    参考一开始的例子我们简单写出下面代码:

    import 'package:flutter/material.dart';
    
    class Increment extends StatefulWidget{
    
      @override
      State<StatefulWidget> createState() {
        return _IncrementState();
      }
    
    }
    
    
    class _IncrementState extends State<Increment> {
    
      int _count = 0;
    
      void _incrementCount() {
        setState(() {
          _count++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return _buildPage();
      }
    
      Widget _buildPage() {
        return MaterialApp(
          home: Scaffold(
            body: Center( 
                child : Text('$_count')
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: _incrementCount,
              tooltip: 'Increment',
              child: Icon(Icons.add),
            ),
          ),
        );
      }
      
    }
    

    这里面需要说明的是多了一个新的 Widget FloatingActionButton。

    可以看到它是作为 Scaffold 自带的一个属性的。

    FloatingActionButton 讲解:

    onPressed 后面是这个按钮点击之后会回调的一个方法。

    tooltip 是长按之后会显示的提示文字。

    child 是这个按钮显示的图标。

    我们修改 main.dart 文件如下,看下效果:

    import 'package:flutter/material.dart';
    
    import 'increment.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Increment();
      }
    }
    
    

    效果如下:

    这里重点的代码是下面:

    setState(() {
          _count++;
    });
    

    它表示将数字加一之后更新界面。

    需要更新界面时需要调用 setState 方法。

    更新数据源可以在 setState 方法里面写。

    5. StatefulWidget 通用模板

    FileName为你文件名的驼峰形式,_FileNameState 里面的 FileName 也是哦~

    import 'package:flutter/material.dart';
    
    class FileName extends StatefulWidget{
    
      @override
      State<StatefulWidget> createState() {
        return _FileNameState();
      }
    
    }
    
    class _FileNameState extends State<FileName> {
    
      @override
      Widget build(BuildContext context) {
        return _buildPage();
      }
    
      Widget _buildPage() {
        //TODO build your widget
      }
      
    }
    

    到了这里你回过头去看新建 Flutter 项目时自动创建的 main.dart 文件就看得懂了。

    6. StatelessWidget vs StatefulWidget

    好了,上面讲解完了 StatelessWidget 和 StatefulWidget,相信大家应该知道如何自定义一个 Widget 了,也知道如何在其他页面引入了。

    但是我们实际上在使用的时候到底是要继承 StatelessWidget 还是 StatefulWidget 呢?

    其实根据名称可以看出取决于你这个 Widget 是有状态还是无状态?

    不过「状态」这个词也不是好理解。

    所以笔者是这样来区分使用 StatelessWidget 还是 StatefulWidget的?

    看界面是否需要更新

    比如我们上面的例子,点击按钮文本更新了,所以我们选择了 StatefulWidget。

    而第一个只是字体调整,界面渲染之后不再需要更新了,所以我们选择了 StatelessWidget。

    所以我们可以认为当界面需要更新时,我们的自定义 Widget 就要继承 StatefulWidget 而不是 StatelessWidget。

    更多阅读:
    Flutter 即学即用系列博客——01 环境搭建
    Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
    Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
    Flutter 即学即用系列博客——04 Flutter UI 初窥

  • 相关阅读:
    【VS开发】【智能语音处理】DTW算法(语音识别)
    【VS开发】【智能语音处理】语音信号处理之(四)梅尔频率倒谱系数(MFCC)
    【VS开发】【智能语音处理】语音信号处理之(四)梅尔频率倒谱系数(MFCC)
    【VS开发】如何移植对话框?
    【VS开发】如何移植对话框?
    【VS开发】模态对话框和非模态对话框
    【VS开发】模态对话框和非模态对话框
    【VS开发】【智能语音处理】Windows下麦克风语音采集
    【VS开发】【智能语音处理】Windows下麦克风语音采集
    【VS开发】【智能语音处理】VS中声音的采集实现
  • 原文地址:https://www.cnblogs.com/nesger/p/10408579.html
Copyright © 2011-2022 走看看