Flutter Widget and Bald

快狗叫車前端團隊發表於2019-09-12

Flutter 是什麼?

我們先來搬運官網的一段介紹,讓大家有一個直觀的認識:

Flutter是谷歌的移動UI框架,可以快速在 iOS 和 Android 上構建高質量的原生使用者介面。
Flutter可以與現有的程式碼一起工作。在全世界,Flutter正在被越來越多的開發者和組織使用,並且Flutter是完全免費、開源的。
複製程式碼

簡而言之

  1. 跨端(移動、Web、桌⾯、嵌⼊式)
  2. ⾼效能(Dart)
  3. ⾼效開發(熱過載)
  4. 富有表現⼒的 UI(Widget)

溫馨提示

  • 搭建開發環境
  • Dart簡介
  • ......

這些我們都不講,今天我們聊一下 Flutter Widget 。讓我們開始吧~

Widget 簡介

概念

Widget 描述了在當前的配置和狀態下,檢視所應該 呈現的樣⼦。當 Widget 的狀態改變時,它會重新構 建其描述(展示的 UI),框架則會對⽐前後變化的 不同,以確定底層渲染樹從⼀個狀態轉換到下⼀個狀 態所需的最⼩更改。

Widget目錄

image

描述元素的配置

示例-1

image

示例-2

image

Widget 結構

image

Widget 組合的結構是樹,所以叫Widget 樹。樹中包含

  • 根Widget
    • WidgetsApp【自定義風格】
    • MaterialApp【基於 WidgetsApp的Material Design 風格(常用)
    • CupertinoApp【基於 WidgetsApp 實現的 iOS 風格】
  • 父Widget
  • 子Widget
// main.dart
import 'package:flutter/material.dart'; //風格需要先匯入哦~
import 'my_home_page_widget.dart';

void main() => runApp(MyApp());  //Flutter會預設把 根Widget 充滿螢幕

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.light(),
      home: MyHomePage(title: 'Vava熊の日記'),
    );
  }
}
複製程式碼

Widget 與 Element

  • Widget樹實際上是一個配置樹,而真正的UI渲染樹是由Element構成。
  • 一個Widget物件可以對應多個Element物件。根據同一份配置(Widget),可以建立多個例項(Element)。
graph LR
Widget配置--> Element1
Widget配置--> Element2
Widget配置--> Element3
Widget配置--> ...
複製程式碼

Widget 狀態分類

因為渲染是很耗效能的,為了提高 Flutter 的幀率,就要儘量減少不必要的 UI 渲染,所以 Flutter 根據 UI 是否有變化,將 Widget 分為StatelessWidget && StatefulWidget

StatelessWidgetStatefulWidget都是直接繼承自Widget類,它們引入了兩種Widget模型,接下來我們將重點介紹一下這兩個類。

StatelessWidget:immutable(狀態不可變)

StatelessWidget是不可變狀態的 Widget 抽象類, 只能在載入/構建 Widget 時才繪製一次,無法基於任何事件或使用者操作重繪。所以 StatelessWidget生命週期就只有一個,即 build 函式。

StatelessWidget の Demo

// main.dart
import 'package:flutter/material.dart';
import 'stateless.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.light(),
      home: MyStatelessApp("123 木頭人,不許動    ——from Vava熊")
    );
  }
}
複製程式碼
//stateless.dart
import 'package:flutter/material.dart';

class MyStatelessApp extends StatelessWidget {
  final String content;
  MyStatelessApp(this.content);
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar:AppBar(
          title: Text('StatelessWidget'),
        ),
        body:Center(
          child: Text(content),
        )
    );
  }
}
複製程式碼

效果圖

image

StatefulWidget 及 State

  • 可變狀態的 Widget
  • 建立 State 物件
  • 多生命週期

StatefulWidget の Demo

每點選文字一次,body文字中就會多一次‘贊’

// main.dart
import 'package:flutter/material.dart';
import 'stateful.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.light(),
      home: MyStatefulApp("Vava熊の一天")
    );
  }
}
複製程式碼
//stateful.dart
import 'package:flutter/material.dart';

class MyStatefulApp extends StatefulWidget {
  String content;
  MyStatefulApp(this.content);

  @override
  State<StatefulWidget> createState() {
    return MyStatefulAppState();
  }
}

class MyStatefulAppState extends State<MyStatefulApp> {
  bool isShowText =true;
  void increment(){
    setState(() {
      widget.content += "贊";
    });
  }
  
  //build() 方法在 didChangeDependencies()(或者 didUpdateWidget() )之後呼叫
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar:AppBar(
          title: Text('StatefulWidget及State'),
        ),
        body:Center(
          child: GestureDetector(
            child: isShowText? Text(widget.content) :null,
            onTap: increment,
           )
        )
    );
  }
  
  //-------only 生命週期 log------------
  //建立 State 物件後要呼叫的第一個方法
  @override
  void initState() {
    super.initState();
    print("initState");
    context.runtimeType;
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("didChangeDependencies");
  }

  //runtimeType 和 Widget.key 都一樣,那麼就會呼叫 didUpdateWidget()。
  @override
  void didUpdateWidget(MyStatefulApp oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("didUpdateWidget");
  }

  // StaefulWidget 從樹中移除時
  @override
  void dispose() {
    super.dispose();
    print("dispose");
  }
  
  //執行 HotReload,就會觸發 reassemble(),這提供了重新初始化在 initState() 方法中準備的任何資料的機會,包括全域性變數。
  @override
  void reassemble() {
    super.reassemble();
    print("reassemble");
  }
}
複製程式碼

效果圖

image

State 的生命週期

在上面的例子中,除了效果外,我們也看到了關於生命週期的備註資訊。

// 控制檯日誌
// 1.第一次 | 新開啟
....
Restarted application in 1,153ms.
flutter: initState
flutter: didChangeDependencies
flutter: reassemble
flutter: didUpdateWidget
...
// 2.我們點選⚡️按鈕熱過載
...
Syncing files to device iPhone Xʀ...
flutter: reassemble
flutter: didUpdateWidget
...
// 3. 移除 widget
...
flutter: reassemble
flutter: dispose
Reloaded 2 of 442 libraries in 117ms.
...
複製程式碼

盜圖小結

image

葵花寶典:如果 UI 需要改變,就用 StatefulWidget。不需要改變,就用 StatelessWidget。

寫在最後の總結

Widget 特點

  • 一切皆 Widget
  • UI的配置資訊
  • 一次性的
  • 輕量的

Widget 應用

Widget 眾多,需要開發者們更多地實踐與效能的關注。 路漫漫其修遠兮,今天也要加油鴨~

關於我們

快狗叫車前端團隊專注前端技術分享,定期推送高質量文章,歡迎關注點贊。
文章同步釋出在公眾號喲,想要第一時間得到最新的資訊,just scan it !

公眾號二維碼

相關文章