1. 程式人生 > >Flutter 即學即用系列博客——05 StatelessWidget vs StatefulWidget

Flutter 即學即用系列博客——05 StatelessWidget vs StatefulWidget

dpa context create idg 渲染 進行 界面 get() 分享圖片

技術分享圖片

前言

上一篇我們對 Flutter UI 有了一個基本的了解。

這一篇我們通過自定義 Widget 來了解下如何寫一個 Widget?

然而 Widget 有兩個,StatelessWidget 和 StatefulWidget,我們要繼承哪一個?

下面讓我們跟著文章來探索一番。

目錄

技術分享圖片

1. StatelessWidget

我們先來看下繼承的 Widget 為 StatelessWidget 的情況。

第一步:新建一個文件 bold_text.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 初窺

技術分享圖片

Flutter 即學即用系列博客——05 StatelessWidget vs StatefulWidget