Flutter 系列博客——05 StatelessWidget vs StatefulWidget

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

前言

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

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

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

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

目錄

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

1. StatelessWidget

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

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

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

這裡文件名後面後綴 .dart 可帶可不帶

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

這裡文件名後面後綴 .dart 可帶可不帶

文件名多個單詞組成用下劃線分隔。

這裡我們演示直接在 lib 文件夾下面創建,實際項目記得文件夾結構的組織哦~

第二步:import 系統包

一般自定義 Widget 都要 import 下面的一個包。

import 'package:flutter/material.dart';

IDE 有自動提示和補全功能,因此不用死記硬背。

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

第三步:自定義一個類繼承自 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 代碼即可。如下圖:

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

第五步:實現 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 官網。

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

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;
}
}
/<statefulwidget>

和 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;
}
}
/<increment>/<statefulwidget>

所以接下來的工作就是類似的。

第六步:實現 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),
),
),
);
}
}
/<increment>/<statefulwidget>

這裡面需要說明的是多了一個新的 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();
}

}

效果如下:

Flutter 系列博客——05 StatelessWidget vs StatefulWidget

這裡重點的代碼是下面:

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
}
}
/<filename>/<statefulwidget>

到了這裡你回過頭去看新建 Flutter 項目時自動創建的 main.dart 文件就看得懂了。

6. StatelessWidget vs StatefulWidget

好了,上面講解完了 StatelessWidget 和 StatefulWidget,相信大家應該知道如何自定義一個 Widget 了,也知道如何在其他頁面引入了。

但是我們實際上在使用的時候到底是要繼承 StatelessWidget 還是 StatefulWidget 呢?

其實根據名稱可以看出取決於你這個 Widget 是有狀態還是無狀態?

不過「狀態」這個詞也不是好理解。

所以筆者是這樣來區分使用 StatelessWidget 還是 StatefulWidget的?

看界面是否需要更新

比如我們上面的例子,點擊按鈕文本更新了,所以我們選擇了 StatefulWidget。

而第一個只是字體調整,界面渲染之後不再需要更新了,所以我們選擇了 StatelessWidget。

所以我們可以認為當界面需要更新時,我們的自定義 Widget 就要繼承 StatefulWidget 而不是 StatelessWidget。

更多閱讀:


分享到:


相關文章: