Flutter基礎(四)開發Flutter應用前需要掌握的Basic Widget

本文首發於公衆號「劉望舒」

關聯繫列
ReactNative入門系列
React Native組件
Flutter基礎系列

前言

學完了Dart語言,接下來就可以學習Widget了,Flutter的UI界面就是由Widget組成的,Widget的數量繁多,因此我會用幾篇文章來專門介紹它,本篇就來介紹Basics Widget。

1.什麼是Widget

Flutter的Widget的設計靈感來自於React,主要目的就是使用Widget構建UI。Widget根據其當前配置和狀態來描述視圖,當Widget的狀態發生更改時,Widget會重建其描述。framework將根據前面的描述進行對比,以確定底層渲染樹從一個狀態轉換到下一個狀態所需的最小更改。
在Flutter中,除了Basics 的文本、圖片、卡片、輸入框這些基礎控件,佈局方式和動畫等也都是由Widget組成的。通過使用不同類型的Widget,就可以實現複雜的界面。
Widget可以翻譯爲部件,粗略的相當於Android中的View。Widget和View不同的是:Widget具有不同的生命週期:它是不可變的,每當Widget或者其狀態發生變化時,Flutter的框架都會創建一個新的Widget實例樹。相比之下,Android中的View會被繪製一次,並且在invalidate調用之前不會重繪。

2.Widget的分類

Widget的分類有很多類別,每個類別下面又包含很多Widget,主要包括以下幾種類別:

  • Basics:在構建第一個Flutter應用程序之前,需要知道的Basics Widget。
  • Material Components:Material Design風格的Widget。
  • Cupertino:iOS風格的Widget。
  • Accessibility:輔助功能Widget。
  • Animation and Motion:動畫和動作Widget。
  • Async:Flutter應用程序的異步Widget。
  • Input:除了在Material Components和Cupertino中的輸入Widget外,還可以接受用戶輸入的Widget。
  • Interaction Models:響應觸摸事件並將用戶路由到不同的視圖中。
  • Layout:用於佈局的Widget。
  • Painting and effects:不改變佈局、大小、位置的情況下爲子Widget應用視覺效果。
  • Scrolling:滾動相關的Widget。
  • Styling:主題、填充相關Widget。
  • Text:顯示文本和文本樣式。

Basics有些特殊,它是由Flutter官方從其他的Widget分類中選取的一些Widget組成的,這些Widget是官方建議開發者構建第一個Flutter應用程序之前,需要知道的,目的是讓開發者更快的入門。比如Row屬於Layout分類,它就被選進了Basics中。本文遵循了Flutter官方的意圖,首先介紹Basics(Basics Widget)。

Widget更多的是以組合的形式存在,比如Container是屬於Layout中的一個Widget,而Container又由LimitedBox、 ConstrainedBox、Align、 Padding、 DecoratedBox、Transform部件組成。 如果要實現Container的自定義效果,可以組合上面這些Widget以及其他簡單的Widget,而不是將Container進行子類化實現。

3.Widget的狀態分類

在Android中,我們可以通過直接更改View來更新視圖。但是在Flutter中,Widget是不可變的並且不會直接更新,而是必須使用Widget的狀態。
Widget有兩種狀態分類分別是無狀態的StatelessWidget和有狀態的StatefulWidget,StatelessWidget是不可變的,設置以後就不可再變化,所有的值都是最終的設置。StatefulWidget可以保存自己的狀態,但是Widget是不可變的,因此需要配合State來保存狀態。
State擁有自己的聲明週期,如下所示:

名稱 狀態
initState create之後被insert到渲染樹時調用的,只會調用一次
didChangeDependencies state依賴的對象發生變化時調用
didUpdateWidget Widget狀態改變時候調用,可能會調用多次
build 構建Widget時調用
deactivate 當移除渲染樹的時調用
dispose Widget即將銷燬時調用

4.根Widget的種類

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
     ...
        ),
      ),
    );
  }
}

上面的MaterialApp就是一個根Widget,也就是Flutter應用程序的第一個Widget,根Widget有以下幾種:

  • WidgetsApp: 如果需要自定義風格,可以使用WidgetsApp。
  • MaterialApp:Material Design風格的Widget。
  • CupertinoApp iOS風格的根Widget。

如果公司沒有特殊要求,這裏建議使用MaterialApp做爲根Widget就可以了。

5.Basics Widget

Basics Widget也就是Basics,主要有以下幾種:

  • Container:一個便利的容器Widget,可以設置Widget的背景、尺寸、定位。
  • Row:在水平方向上佈置子窗口Widget列表。
  • Column:在垂直方向上佈置子窗口Widge列表。
  • Image:顯示圖像的Widget
  • Text:單一樣式的文本。
  • Icon:符合Material Design設計規範的圖標
  • RaisedButton:符合Material Design設計規範的凸起按鈕。
  • Scaffold:實現Basics 的Material Design佈局結構。
  • Appbar:Material Design的應用欄。
  • FlutterLogo:以Widget形式來展示一個Flutter圖標,可以調整樣式。
  • Placeholder:繪製一個框,爲將來添加的Widget的佔位。

這裏選擇一些我們必須要掌握的Basics Widget來進行講解。

5.1 代碼模板和主題

爲了更好的理解這些Basics Widget,我們需要寫一些例子,這些例子需要一個代碼模板,方便測試和學習。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(//1
      title: 'Welcome to Flutter',
      home: Scaffold(//2
        appBar: AppBar(//3
          title: Text('Basics Widget'),
        ),
        body:
          Padding(
            padding: EdgeInsets.all(40.0),
            child:  Text('在這裏編寫和測試其他Basics Widget'),
          ),
      ),
    );
  }
}

上面的代碼是稍微改動了官方的Hello World代碼,便於測試,具體的代碼含義已經在Flutter基礎(二)Flutter開發環境搭建和Hello World中講過了,這裏結合本文要講的內容再說點細節。註釋1處的MaterialApp屬於Material Components類別中的Widget,MaterialApp中包含了實現Material Design的應用程序所需要的Widget。
註釋2和3處的Scaffold和AppBar同樣也是Material Components類別中的Widget,Scaffold實現了Material Design佈局結構,AppBar是Material Design的應用欄,它們會在下一篇文章介紹Material Components時進行講解。效果如下圖所示:

5.2 文本

在4.1小節中已經用了Text,還可以定義樣式:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Basics Widget'),
        ),
        body: Padding(
          padding: EdgeInsets.all(60.0),
          child: Text(
            '文本樣式',
            style: TextStyle(
              fontSize: 16.0, 
              color: Colors.indigo,
              fontStyle: FontStyle.normal,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ),
    );
  }
}

這次爲了便於理解列出了全部的代碼,此後的舉例只列出改變的部分
通過TextStyle來定義文本的樣式,效果如下:
[外鏈圖片轉存失敗(img-zzx5co4C-1564404135332)(https://s2.ax1x.com/2019/05/27/VZrQ3V.png)]

5.3 圖片

Image的構造函數有多種:

  • new Image:從ImageProvider獲取圖片
  • new Image.asset:使用key從AssetBundle獲取圖片
  • new Image.network:加載網絡圖片
  • new Image.file:從文件中獲取圖片
  • new Image.memory:用於從Uint8List獲取圖片

Image的屬性有很多種,主要的屬性爲fit,用於表示圖片的填充模式,參數類型爲BoxFit,BoxFit的取值主要有以下幾種,示例圖片來自flutter官方。

contain
全圖顯示,保持原比例。

cover
全圖充滿,可能拉伸也可能被裁剪

fill
全圖顯示,通過拉伸來充滿目標框

fitHeight
圖片高度充滿目標框,可能拉伸也可能被裁剪

fitWidth
圖片寬度充滿目標框,可能拉伸也可能被裁剪

none
保持圖片的原始大小,剪裁掉位於目標框外的圖片部分

scaleDown
與contain縮小圖像的方式相同,只不過會在必要時縮小以確保圖片完全在目標框內,如果不縮小等同於none。

child: Image.network(
            "https://upload-images.jianshu.io/upload_images/1417629-53f7d0902457cbe6.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
            width: 260,
            height: 100,
            fit: BoxFit.fill,
          ),

效果如下圖所示:
[外鏈圖片轉存失敗(img-xtOHVgzL-1564404135334)(https://s2.ax1x.com/2019/05/27/VZr8uF.png)]

5.4 凸起按鈕

凸起按鈕RaisedButton是符合Material Design設計規範的按鈕,可以通過onPressed來回調按鈕的點擊。

RaisedButton(
            onPressed: () => print("onPressed"),
            color: Colors.lightBlueAccent,
            child: Text('RaisedButton', style: TextStyle(fontSize: 10)),
          ),

除了使用RaisedButton,flutter還提供了其他的按鈕,比如FlatButton、IconButton、FloatingActionButton等等,它們的使用方法和RaisedButton大同小異,這裏就不再贅述。

5.5 其他Widget

Basics Widget中的還有Row、Column、Container等Widget,這裏簡單介紹下。

Row
Row用於在水平方向顯示數組中的子元素Widget。

    child: Row(
            children: <Widget>[
              Icon(Icons.access_alarm),
              Icon(Icons.add_a_photo),
              Icon(Icons.add_call),
            ],
          ),

垂直方向顯示數組中的子元素Widget用Column,使用方法和Row一樣。這裏需要提到的是Expanded,可以用Expanded來配合Row和Column使用,用來填充剩餘的空間。

        Row(
            children: <Widget>[
              Icon(Icons.access_alarm),
              Icon(Icons.add_a_photo),
              Icon(Icons.add_call),
              Expanded(
                child: FittedBox(
                  fit: BoxFit.contain,
                  child: const FlutterLogo(),
                ),
                flex: 2,
              ),
              Expanded(
                child: Text(
                  "佔剩餘部分的三分之一",
                ),
                flex: 1,
              ),
            ],
          ),

其中的Expanded的作用是在自己的尺寸範圍內縮放並且調整child位置,使得child適合其尺寸。FlutterLogo是Basics Widget中的一種,用於展示Flutter圖標。使用flex可以調整兩個Expanded的佔比。

Container
一個便利的容器Widget,可以設置Widget的背景、尺寸、定位。描述起來有些抽象,可以理解它和Android中的ViewGroup差不多。

      Container(
              decoration:BoxDecoration(
                color: Colors.lightGreen
              ),
            child: Text('Container'),
            padding: EdgeInsets.all(36.0),
            margin: EdgeInsets.all(10.0),
          ),

Container的padding和margin屬性和Android中的作用是類似的:

總結

本文主要介紹了什麼是Widget、Widget的分類、Basics Widget。因爲Widget的數量繁多,官方將Widget進行了分類,並將需要先了解的Widget歸入到了Basics Widget中,後續文章會介紹其他的Widge分類。


這裏不僅分享大前端、Android、Java等技術,還有程序員成長類文章。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章