[Flutter]flutter基礎(chǔ)之組件基礎(chǔ)(五)

一、概述

前面幾篇文章介紹了一些基本的Flutter Widget 庵朝,現(xiàn)在開始介紹一下前面一直用到但沒做過多說明的 MaterialApp 吗冤,Scaffold 和一些布局組件又厉,因為后面的很多 Widget 中要使用部分布局 Widget , 所以這里插入先對這些 Widget 做下講解欣孤。

為了方便的創(chuàng)建出特定風(fēng)格的應(yīng)用程序馋没,F(xiàn)lutter 包裝了創(chuàng)建應(yīng)用程序的 Widget :MaterialApp 用于創(chuàng)建 Material 設(shè)計風(fēng)格( Android 風(fēng)格 )的應(yīng)用程序,CupertinoApp 用于創(chuàng)建 ios 設(shè)計風(fēng)格的應(yīng)用程序降传。這里首先介紹下 MaterialApp 篷朵,以后在對 CupertinoApp 做說明。

二婆排、MaterialApp

MaterialApp 是一個 Widget 声旺,代表使用 Material 設(shè)計風(fēng)格的應(yīng)用。在 Flutter 中創(chuàng)建一個Material 設(shè)計風(fēng)格的移動應(yīng)用程序段只,應(yīng)首先在 Widget 樹的根插入 MaterialApp Widget 腮猖。MaterialApp 繼承自 StatefulWidget 郭脂,是一個有狀態(tài)的 Widget 感昼,雖然在其構(gòu)造函數(shù)中沒有必傳參數(shù),但是有很多命名可選參數(shù)是不能為 null 的塌鸯,必須為他們分配值炕婶,這是通過斷言的方式的實現(xiàn)的姐赡。MaterialApp 主要用來設(shè)置應(yīng)用程序啟動時的首界面,主題柠掂,路由功能项滑,本地化語言環(huán)境,文本的方向等涯贞。

其構(gòu)造函數(shù)如下:

  const MaterialApp({
    Key key,
    //GlobalKey<NavigatorState>類型可選命名參數(shù)枪狂,構(gòu)建導(dǎo)航器時要使用的鍵
    this.navigatorKey,
    //Widget類型可選命名參數(shù),應(yīng)用打開時宋渔,要顯示的第一個頁面(主頁)
    this.home,
    //Map<String, WidgetBuilder>類型可選命名參數(shù)州疾,路由,用于定義應(yīng)用中的頁面跳轉(zhuǎn)
    this.routes = const <String, WidgetBuilder>{},
    //String類型可選命名參數(shù)皇拣,初始化路由孝治,用于在構(gòu)建了導(dǎo)航器的情況下,設(shè)置要顯示的第一個路由的名稱
    this.initialRoute,
    //RouteFactory類型可選命名參數(shù)审磁,在應(yīng)用導(dǎo)航到命名路由時使用的路由生成器回調(diào)
    this.onGenerateRoute,
    //RouteFactory類型可選命名參數(shù)谈飒,當(dāng)onGenerateRoute未能生成路由(初始路由除外)時調(diào)用
    this.onUnknownRoute,
    //List<NavigatorObserver>類型可選命名參數(shù),為此應(yīng)用程序創(chuàng)建的導(dǎo)航器的觀察器列表
    this.navigatorObservers = const <NavigatorObserver>[],
    //TransitionBuilder類型可選命名參數(shù)态蒂,用于將小部件插入到Navigator上方并且在WidgetApp創(chuàng)建
    //的其他小部件下方的構(gòu)建器杭措,或用于完全替換Navigator的構(gòu)建器
    this.builder,
    //String類型可選命名參數(shù),用于標(biāo)識應(yīng)用
    this.title = '',
    //GenerateAppTitle類型可選命名參數(shù)钾恢,如果非空手素,則調(diào)用該回調(diào)函數(shù)來生成應(yīng)用程序的標(biāo)題字符串鸳址,否則使用標(biāo)題
    //onGenerateTitle上下文參數(shù)包括WidgetsApp的Localizations小部件,因此該回調(diào)可用于生成本地化的標(biāo)題
    this.onGenerateTitle,
    //Color類型可選命名參數(shù)泉懦,操作系統(tǒng)界面中用于應(yīng)用程序的主要顏色
    this.color,
    //ThemeData類型可選命名參數(shù)稿黍,用于設(shè)置應(yīng)用的主題(外觀)
    this.theme,
    //ThemeData類型可選命名參數(shù),設(shè)置暗模式主題
    this.darkTheme,
    //ThemeMode類型可選命名參數(shù)崩哩,用于確定在同時設(shè)置了 theme 和 darkTheme 的情況下使用哪個主題
    this.themeMode = ThemeMode.system,
    //Locale類型可選命名參數(shù)巡球,用于設(shè)置應(yīng)用程序本地化初始語言
    this.locale,
    //Iterable<LocalizationsDelegate>類型可選命名參數(shù),應(yīng)用程序本地化代理
    this.localizationsDelegates,
    //LocaleListResolutionCallback類型可選命名參數(shù)邓嘹,該回調(diào)負(fù)責(zé)在應(yīng)用啟動時
    //以及用戶更改設(shè)備的區(qū)域設(shè)置時選擇應(yīng)用的區(qū)域設(shè)置
    this.localeListResolutionCallback,
    //LocaleResolutionCallback類型可選命名參數(shù)酣栈,這個回調(diào)傳遞給由這個小部件構(gòu)建的WidgetsApp
    this.localeResolutionCallback,
    //Iterable<Locale>類型可選命名參數(shù),應(yīng)用支持的本地化語言汹押,
    //不能為空矿筝,默認(rèn)的語言解析算法根據(jù)設(shè)置順序進(jìn)行解析
    this.supportedLocales = const <Locale>[Locale('en', 'US')],
    //bool類型可選命名參數(shù),是否顯示網(wǎng)格(可用于調(diào)試UI)棚贾,僅檢查模式可用
    this.debugShowMaterialGrid = false,
    //bool類型可選命名參數(shù)窖维,是否顯示性能提示
    this.showPerformanceOverlay = false,
    //bool類型可選命名參數(shù),是否打開柵格緩存圖像
    this.checkerboardRasterCacheImages = false,
    //bool類型可選命名參數(shù)妙痹,檢查渲染到屏幕外的圖層
    this.checkerboardOffscreenLayers = false,
    //bool類型可選明敏參數(shù)是否顯示語義調(diào)試
    this.showSemanticsDebugger = false,
    //bool類型可選命名參數(shù)铸史,在檢查模式下,在屏幕右上角是否顯示 DEBUG 橫幅细诸,發(fā)布模式無效
    this.debugShowCheckedModeBanner = true,
  })

第一個 Key 參數(shù),是作為 Widget 陋守、Element 震贵、SemanticsNode 的標(biāo)識符,其作用是水评,當(dāng)現(xiàn)有元素的鍵與當(dāng)前 Widget 的鍵相同時,會使用新的 Widget 更新現(xiàn)有的元素。前面介紹過的構(gòu)造參數(shù)都有這個參數(shù),這里做下說明。

在這些屬性中壮池,home 橙依、routes 卵渴、onGeneratedRoutebuilder 在創(chuàng)建 MaterialApp 時,至少有一個必須進(jìn)行設(shè)置纺蛆,不能為 null 字支,否則會報異常欠雌。對于指定應(yīng)用的首界面腌歉,如果在 MaterialApp 提供了 home 馍驯,則使用 home 指定的 Widget 擂煞。如果 homenull 蒿涎,則尋找 routes 中的 "/" 玻淑,如果進(jìn)行了設(shè)置,則使用 "/" 對應(yīng)的 Widget 作為首界面。如果routes 中沒有設(shè)置 "/" 岔擂,且沒有設(shè)置 home 规婆,則調(diào)用回調(diào)函數(shù) onGenerateRoute 操漠,如果提供了,它會作為首界面進(jìn)行回調(diào)唆姐。如果沒有設(shè)置 onGenerateRoute 拗慨,也沒有提供 builder ,則調(diào)用 onUnknownRoute 奉芦。如果提供了 builder 則會覆蓋以上流程中設(shè)置的首界面赵抢。

只提供 home 如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FirstPage(),
    );;
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 1"));
  }
}

路由 ( routes ) 用來設(shè)置頂級導(dǎo)航的不同界面。如果只提供了 routes 声功,則必須包含 "/" 烦却,表示應(yīng)用啟動的第一個界面,home"/" 不能同時指定先巴。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        "/" : (context)=> FirstPage(),
        "/second" : (context)=> SecondPage(),
        "/third" : (context)=> ThirdPage(),
      },
      initialRoute: "/",
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 1"));
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 2"));
  }
}

class ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 3"));
  }
}

onGenerateRoute 的類型是 RouteFactory 其爵,其是一個 Function ,原型為 Route<dynamic> Function(RouteSettings settings) 伸蚯。 使用如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      onGenerateRoute: (settings) {
        return MaterialPageRoute(
          builder: (context){
            return Center(
              child: Text("Page 1"),
            );
          },
        );
      },
    );
  }
}

builder 的類型是 TransitionBuilder 摩渺,也是一個 Function ,原型為:Widget Function(BuildContext context, Widget child) 剂邮。使用如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) {
        return Center(
          child: Text("Page 1"),
        );
      },
    );
  }
}

如果以上都沒有設(shè)置就會調(diào)用 onUnknownRoute 摇幻,其類型也是一個 RouteFactory ,使用方式與 onGenerateRoute 相同。onUnknownRoute 主要用于錯誤處理绰姻,用于描述未找到 Widget 枉侧,類似 404 錯誤頁面設(shè)置。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      onUnknownRoute: (settings) {
        return MaterialPageRoute(
          builder: (context){
            return Center(
              child: Text("沒有找到路由"),
            );
          },
        );
      },
    );
  }
}

以上正確設(shè)置的效果如下圖:

2020310627.jpg

現(xiàn)在的界面是沒有導(dǎo)航的狂芋,在一個完整的應(yīng)用程序中棵逊,一般都會有導(dǎo)航組件,在 Flutter 中银酗,需要使用 Scaffold 來組織界面布局結(jié)構(gòu)辆影。MaterialApp 中的其他屬性,在介紹完 Scaffold 后統(tǒng)一說明黍特。

三蛙讥、Scaffold Widget

Scaffold 稱為腳手架 Widget ,用于組織界面布局灭衷,其中包含了創(chuàng)建一個應(yīng)用程序的幾乎所有東西次慢。構(gòu)造方法如下:

const Scaffold({
  Key key,
  //PreferredSizeWidget類型可選命名參數(shù),應(yīng)用頂部的導(dǎo)航欄
  this.appBar,
  //Widget類型可選命名參數(shù)翔曲,主界面顯示的Widget
  this.body,
  //Widget類型可選命名參數(shù)迫像,懸浮在界面上方的按鈕
  this.floatingActionButton,
  //FloatingActionButtonLocation類型可選命名參數(shù),設(shè)置懸浮按鈕的位置
  this.floatingActionButtonLocation,
  //FloatingActionButtonAnimator類型可選命名參數(shù)瞳遍,將懸浮按鈕移動到一個新的位置
  this.floatingActionButtonAnimator,
  //List<Widget>類型可選命名參數(shù)闻妓,在界面底部顯示的一組按鈕,呈現(xiàn)在bottomNavigationBar上方
  this.persistentFooterButtons,
  //Widget類型可選命名參數(shù)掠械,抽屜Widget由缆,顯示在側(cè)面的面板,入口在頂部導(dǎo)航左側(cè)
  this.drawer,
  //Widget類型可選命名參數(shù)猾蒂,抽屜Widget均唉,顯示在側(cè)面的面板,入口在頂部導(dǎo)航右側(cè)
  this.endDrawer,
  //Widget類型可選命名參數(shù)肚菠,底部應(yīng)用欄或?qū)Ш綑?  this.bottomNavigationBar,
  //Widget類型可選命名參數(shù)舔箭,要顯示的永久性底部工作表
  this.bottomSheet,
  //Color類型可選命名參數(shù),設(shè)置整個Scafflod組件的顏色
  this.backgroundColor,
  //bool類型參數(shù)蚊逢,已棄用层扶,使用resizeToAvoidBottomInset
  this.resizeToAvoidBottomPadding,   //已棄用
  //bool類型可選命名參數(shù),指定當(dāng)鍵盤出現(xiàn)時时捌,正文是否應(yīng)該調(diào)整大小
  this.resizeToAvoidBottomInset,
  //bool類型可選命名參數(shù)怒医,Scaffold是否在屏幕頂部顯示炉抒,如果為true奢讨,
  //則appBar的高度將擴(kuò)展為屏幕狀態(tài)欄的高度,即MediaQuery的頂部填充
  this.primary = true,
  //DragStartBehavior類型可選命名參數(shù),確定處理拖動啟動行為的方式
  this.drawerDragStartBehavior = DragStartBehavior.start,
  //bool類型可選命名參數(shù)拿诸,如果為真扒袖,并且指定了底部導(dǎo)航欄或持久底托按鈕,
  //則主體延伸到腳手架的底部亩码,而不是僅延伸到底部導(dǎo)航欄或持久底托按鈕的頂部
  this.extendBody = false,
  //bool類型可選命名參數(shù)季率,如果為true,并且指定了一個應(yīng)用欄描沟,
  //則主體的高度將被擴(kuò)展為包括應(yīng)用欄的高度飒泻,并且主體的頂部與應(yīng)用欄的頂部對齊
  this.extendBodyBehindAppBar = false,
  //Color類型可選命名參數(shù),抽屜打開時吏廉,主體遮罩的顏色
  this.drawerScrimColor,
  //double類型可選命名參數(shù)泞遗,滑動打開抽屜的有效拖動寬度,為0則滑動無法打開抽屜
  this.drawerEdgeDragWidth,
})

其中席覆,appBar 的類型為 PreferredSizeWidget 史辙,是一個抽象類,需要使用其子類 AppBar 來創(chuàng)建頂部導(dǎo)航佩伤,body 是界面顯示的主體部分聊倔,可以使用任何組件,具體使用什么取決于應(yīng)用程序要實現(xiàn)的功能生巡。

AppBar 構(gòu)造函數(shù)如下:

AppBar({
  Key key,
  //Widget類型可選命名參數(shù)耙蔑,要在標(biāo)題前顯示的小部件(頂部導(dǎo)航左側(cè)的Widget)
  this.leading,
  //bool類型可選命名參數(shù),leading如果為空孤荣,是否嘗試按時前導(dǎo)Widget
  this.automaticallyImplyLeading = true,
  //Widget類型可選命名參數(shù)纵潦,用于設(shè)置導(dǎo)航欄標(biāo)題顯示的內(nèi)容
  this.title,
  //List<Widget>類型可選命名參數(shù),要在標(biāo)題小部件后顯示的小部件(頂部導(dǎo)航右側(cè)的Widget)
  this.actions,
  //Widget類型可選命名參數(shù)垃环,該小部件堆疊在頂部導(dǎo)航和選項卡欄的后面邀层,通常為FlexibleSpaceBar類型。
  //它的高度將與應(yīng)用頂部導(dǎo)航欄的整體高度相同
  this.flexibleSpace,
    //PreferredSizeWidget類型可選命名參數(shù)遂庄,應(yīng)用程序?qū)Ш綑诘撞抗ぞ邫诹仍海ǔ門abbar  
  this.bottom,
  //double類型可選命名參數(shù),相對于其父應(yīng)用程序欄放置的z坐標(biāo)
  this.elevation,
  //ShapeBorder類型可選命名參數(shù)涛目,形狀設(shè)置
  this.shape,
  //Color類型可選命名參數(shù)秸谢,導(dǎo)航欄顏色
  this.backgroundColor,
  //Brightness類型可選命名參數(shù),導(dǎo)航欄亮度
  this.brightness,
  //IconThemeData類型可選命名參數(shù)霹肝,導(dǎo)航欄圖標(biāo)顏色估蹄、不透明度、大小設(shè)置
  this.iconTheme,
  //IconThemeData類型可選命名參數(shù)沫换,應(yīng)用程序欄中出現(xiàn)的圖標(biāo)的顏色臭蚁、不透明度和大小。
  //只有當(dāng)動作的主題不同于應(yīng)用程序欄主窗口中出現(xiàn)的圖標(biāo)時,才應(yīng)使用此選項
  this.actionsIconTheme,
  //TextTheme類型可選命名參數(shù)垮兑,應(yīng)用程序頂部導(dǎo)航欄中用于文本的排版樣式冷尉。
  //通常,這與亮度背景顏色系枪、圖標(biāo)主題一起設(shè)置
  this.textTheme,
  //bool類型可選命名參數(shù)雀哨,此應(yīng)用程序欄是否顯示在屏幕頂部
  this.primary = true,
  //bool類型可選命名參數(shù),標(biāo)題是否居中顯示
  this.centerTitle,
  //double類型可選命名參數(shù)私爷,水平軸上標(biāo)題內(nèi)容周圍的間距雾棺。即使沒有前導(dǎo)內(nèi)容或動作,
  //也會應(yīng)用此間距衬浑。如果希望title占用所有可用空間垢村,請將該值設(shè)置為0.0
  this.titleSpacing = NavigationToolbar.kMiddleSpacing,
  //double類型可選命名參數(shù),應(yīng)用程序頂部導(dǎo)航欄的工具欄部分有多不透明
  this.toolbarOpacity = 1.0,
  //double類型可選命名參數(shù)嚎卫,應(yīng)用程序欄底部有多不透明
  this.bottomOpacity = 1.0,
})

通過構(gòu)造函數(shù)可以發(fā)現(xiàn)嘉栓,無論 Scaffold 還是 AppBar 都沒有必須要設(shè)置的必傳參數(shù),直接使用就可以拓诸∏值瑁基本的使用方式如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
      ),
    );;
  }
}

效果如下:

20203101018.jpg

AppBar 布局位置如下圖所示:

app_bar.jpg

基本屬性設(shè)置:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: Icon(Icons.print),   //頂部導(dǎo)航欄左側(cè)Widget
          automaticallyImplyLeading: false,
          title: Text("Page 1"),   //頂部導(dǎo)航欄標(biāo)題
          actions: <Widget>[   //頂部導(dǎo)航欄右側(cè)Widget List
            IconButton(icon: Icon(Icons.add), onPressed: (){},),
          ],
          backgroundColor: Colors.amber,   //頂部導(dǎo)航背景色
          brightness:Brightness.light,
          iconTheme: IconThemeData(color: Colors.lightGreen, opacity: 1, size: 30), //設(shè)置頂部導(dǎo)航欄的Icon圖標(biāo)屬性
          textTheme: TextTheme(title: TextStyle(color: Colors.red)),   //頂部導(dǎo)航文本樣式
          centerTitle: true,    //居中顯示標(biāo)題
        ),
      ),
    );;
  }
}

效果如下圖:

2020311643.jpg

AppBar 中的 bottom 屬性,是顯示在頂部導(dǎo)航底部的 Widget奠支,通常使用 TabBar 馋辈,是一個水平顯示的 Widget 。TabBar 通常也與 TabBarView 一起使用倍谜。

TabBar 構(gòu)造方法如下:

const TabBar({
  Key key,
  //List<Widget>類型必傳參數(shù)迈螟,選項卡顯示的Widget,通常為Tab尔崔。此list長度必須與控制器的
  //TabController.length和TabBarView.children列表的長度匹配
  @required this.tabs,
  //TabController類型可選命名參數(shù)答毫,用于控制TabBar選項卡與TabBarView界面切換狀態(tài)。如果不提供此參數(shù)季春,
  //需要使用DefaultTabController
  this.controller,
  //bool類型可選命名參數(shù)洗搂,菜單標(biāo)簽是否可以橫向滾動
  this.isScrollable = false,
  //Color類型可選命名參數(shù),被選中的選項卡下方線條的顏色
  this.indicatorColor,
  //double類型可選命名參數(shù)载弄,被選中的選項卡下方線條的粗細(xì)
  this.indicatorWeight = 2.0,
  //EdgeInsetsGeometry類型可選命名參數(shù)耘拇,被選中的選項卡下方線條的水平填充間距
  this.indicatorPadding = EdgeInsets.zero,
  //Decoration類型可選命名參數(shù),用于定義選項卡指示器的樣式
  this.indicator,
  //TabBarIndicatorSize類型可選命名參數(shù)宇攻,選項卡指示器的大小
  this.indicatorSize,
  //Color類型可選命名參數(shù)惫叛,選項卡標(biāo)簽顏色
  this.labelColor,
  //TextStyle類型可選命名參數(shù),選項卡標(biāo)簽文本顏色
  this.labelStyle,
  //EdgeInsetsGeometry類型可選命名參數(shù)逞刷,選項卡每個標(biāo)簽的內(nèi)邊距
  this.labelPadding,
  //Color類型可選命名參數(shù)嘉涌,未選中的選項卡標(biāo)簽的顏色
  this.unselectedLabelColor,
  //TextStyle類型可選命名參數(shù)妻熊,未選中選項卡標(biāo)簽的文本樣式
  this.unselectedLabelStyle,
  //DragStartBehavior類型可選命名參數(shù),用于定義處理拖動開始行為的方式
  this.dragStartBehavior = DragStartBehavior.start,
  //ValueChanged<int>類型可選命名參數(shù)洛心,點擊選顯卡標(biāo)簽時的回調(diào)函數(shù)
  this.onTap,
})

其中 tabslist 使用的 Tab 是一個無狀態(tài) Widget ,構(gòu)造方法如下:

const Tab({
  Key key,
  //String類型可選命名參數(shù)题篷,要顯示的文本
  this.text,
  //Widget類型可選命名參數(shù)词身,要顯示圖標(biāo)
  this.icon,
  //Widget類型可選命名參數(shù),為用作標(biāo)簽的Widget
  this.child,
})

TabBarcontrollerTabController 類型番枚。其提供的構(gòu)造方法如下:

TabController({ 
  //int類型可選命名參數(shù)法严,不能為null,用于設(shè)置初始化狀態(tài)選項卡的被選中下標(biāo)葫笼,從0開始
  int initialIndex = 0, 
  //int類型必傳參數(shù)深啤,選項卡選項的總數(shù)
  @required this.length, 
  //TickerProvider類型必傳參數(shù),其為抽象類路星,需要使用其子類SingleTickerProviderStateMixin溯街,
  //下面具體說明
  @required TickerProvider vsync 
}): assert(length != null && length >= 0),
      assert(initialIndex != null && initialIndex >= 0 && (length == 0 || initialIndex < length)),
      _index = initialIndex,
      _previousIndex = initialIndex,
      _animationController = AnimationController.unbounded(
        value: initialIndex.toDouble(),
        vsync: vsync,
      );

這里需要特殊說明的是 vsync 參數(shù),從初始化列表可以看出洋丐,其是賦值給 AnimationController.unbounded 的構(gòu)造方法中的 vsync 呈昔。AnimationController 是一個動畫控制器,是用來控制和生成動畫的友绝。vsyncAnimationController.unbounded 構(gòu)造方法的必傳參數(shù)堤尾。vsyncTickerProvider 類型,其為抽象類迁客,不能直接使用郭宝,根據(jù)官方文檔的說明如下:

If you are creating an AnimationController from a State, then you can use the TickerProviderStateMixin and SingleTickerProviderStateMixin classes to obtain a suitable TickerProvider.

意思是:如果從一個狀態(tài)類( State )中創(chuàng)建 AnimationController ,可以使用 TickerProviderStateMixinSingleTickerProviderStateMixin 來獲取一個適合的 TickerProvider 掷漱。

如果在狀態(tài)的聲明周期中有多個 AnimationController 粘室,則使用 TickerProviderStateMixin 。如果只有一個 AnimationController 卜范,則使用 SingleTickerProviderStateMixin 效率更高育特。使用方法為混合該類,然后將 this 設(shè)置給 vsync 即可先朦。官方說明地址為:https://api.flutter.dev/flutter/widgets/SingleTickerProviderStateMixin-mixin.html 缰冤。

使用 TabController 的目的是關(guān)聯(lián) TabBarTabBarViewTabBarView 是一個頁面視圖喳魏,用于顯示與當(dāng)前選擇的選項卡對應(yīng)的 Widget 棉浸。TabBarView 為一個有狀態(tài)的 Widget ,其構(gòu)造方法如下:

const TabBarView({
  Key key,
  //List<Widget>類型必傳參數(shù)刺彩,用于設(shè)置每個選項卡標(biāo)簽對應(yīng)的Widget
  @required this.children,
  //TabController類型可選命名參數(shù)迷郑,用于關(guān)聯(lián)TabBar和TabBarView枝恋,設(shè)置動畫狀態(tài)
  this.controller,
  //ScrollPhysics類型可選命名參數(shù),設(shè)置頁面視圖應(yīng)該如何響應(yīng)用戶輸入
  this.physics,
  //DragStartBehavior類型可選命名參數(shù)嗡害,確定處理拖動開始行為的方式
  this.dragStartBehavior = DragStartBehavior.start,
}) 

TabBar 的使用方式如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyAppTabPage(),
    );;
  }
}

class MyAppTabPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyAppTabPageState();
  }
}

class _MyAppTabPageState extends State<MyAppTabPage> with SingleTickerProviderStateMixin {

  final List _tabMenu = <Tab>[ Tab(text: "菜單1"), Tab(text: "菜單2",)];
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: _tabMenu.length, vsync: this, initialIndex: 0);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),   //頂部導(dǎo)航欄標(biāo)題
        bottom: TabBar(
          tabs: _tabMenu,
          controller: _tabController,
          onTap: (value) {print(value);},
        ),
      ),
      body: TabBarView(
        children: <Widget>[
          Center(child: Text("Page 1", style: TextStyle(fontSize: 60, color: Colors.yellow),),),
          Center(child: Text("Page 2", style: TextStyle(fontSize: 60, color: Colors.yellow),),),
        ],
        controller: _tabController,
      ),
    );
  }
}

其中 initState() 方法為當(dāng)對象插入到 Widget 樹中時調(diào)用焚碌,僅執(zhí)行一次,做數(shù)據(jù)的初始化操作霸妹,后續(xù)會詳細(xì)介紹十电。

執(zhí)行結(jié)果如下圖:

20203121030.jpg

上面說過,如果在 TabBar 中不提供 controller 叹螟,可以使用 DefaultTabController 鹃骂。因為 TabController 是一個監(jiān)聽狀態(tài)的控制器,其繼承關(guān)系如下:

TabController < ChangeNotifier < Object  

其不是一個 Widget 罢绽,當(dāng)共享顯示創(chuàng)建 TabController 不太方便時可以使用 DefaultTabController 畏线。其繼承自 StatefulWidget ,是一個有狀態(tài)的 Widget 良价,構(gòu)造方法如下:

const DefaultTabController({
  Key key,
  //int類型必傳參數(shù)寝殴,選項卡選項的總數(shù)
  @required this.length,
  //int類型可選命名參數(shù),不能為null明垢,用于設(shè)置初始化狀態(tài)選項卡的被選中下標(biāo)杯矩,從0開始
  this.initialIndex = 0,
  //Widget類型必傳參數(shù),要顯示的Widget
  @required this.child,
})

使用方式如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyAppTabPage(),
    );;
  }
}

class MyAppTabPage extends StatelessWidget {

  final List _tabMenu = <Tab>[ Tab(text: "菜單1"), Tab(text: "菜單2",)];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: _tabMenu.length,
      child: Scaffold(
        appBar: AppBar(
          title: Text("Page 1"),
          bottom: TabBar(
            tabs: _tabMenu,
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            Center(child: Text("Page 1", style: TextStyle(fontSize: 60, color: Colors.yellow),),),
            Center(child: Text("Page 2", style: TextStyle(fontSize: 60, color: Colors.yellow),),),
          ],
        ),
      ),
    );
  }
}

實現(xiàn)效果與上述相同袖外。

關(guān)于 floatingActionButton 史隆,其為一個懸浮按鈕,通常使用 FloatingActionButton 曼验。前面介紹 Button 的文章做過基礎(chǔ)的具體說明泌射,地址為:http://www.mwpush.com/content/aa8d162.html 。在 Scaffold 中的 floatingActionButton 用于特定位置鬓照,會懸浮于 body 之上熔酷。可以對其做一些屬性設(shè)置豺裆,比如位置等拒秘。使用如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyFirstPage(),
    );;
  }
}

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("點擊");
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

效果如下圖:

20203121138.jpg

其中 FloatingActionButtonLocation 用來設(shè)置浮動按鈕的位置,有以下幾種位置可以選擇使用:

//在屏幕底部末端浮動臭猜,不設(shè)置位置參數(shù)躺酒,默認(rèn)使用此參數(shù)
static const FloatingActionButtonLocation endFloat = _EndFloatFloatingActionButtonLocation();

//在屏幕底部居中浮動
static const FloatingActionButtonLocation centerFloat = _CenterFloatFloatingActionButtonLocation();

//在屏幕底部末端,浮動在Scaffold.bottomNavigationBar上方蔑歌,以便浮動操作按鈕的中心與
//底部導(dǎo)航欄的頂部對齊羹应。
//如果Scaffold.bottomNavigationBar的值為BottomAppBar,則底部應(yīng)用欄可以設(shè)置一個凹口次屠,
//以容納浮動按鈕园匹,沒有底部欄不建議使用此位置
static const FloatingActionButtonLocation endDocked = _EndDockedFloatingActionButtonLocation();

//在屏幕底部居中雳刺,浮動在Scaffold.bottomNavigationBar上方,以便浮動操作按鈕的中心與
//底部導(dǎo)航欄的頂部對齊裸违。
//如果Scaffold.bottomNavigationBar的值為BottomAppBar掖桦,則底部應(yīng)用欄可以設(shè)置一個凹口,
//以容納浮動按鈕供汛,沒有底部欄不建議使用此位置
static const FloatingActionButtonLocation centerDocked = _CenterDockedFloatingActionButtonLocation();

//在屏幕上方開始位置枪汪,Scaffold.appBar和Scaffold.body之間的過渡上浮動
static const FloatingActionButtonLocation startTop = _StartTopFloatingActionButtonLocation();

//在屏幕上方開始位置,Scaffold.appBar和Scaffold.body之間的過渡上浮動紊馏,其位置與startTop相同料饥。
//但是蒲犬,如果FloatingActionButton.mini設(shè)置為true朱监,并在Scaffold.body的ListView中的
//ListTile.ListTiles的前導(dǎo)槽的CircleAvatars對齊,請考慮使用miniStartTop
static const FloatingActionButtonLocation miniStartTop = _MiniStartTopFloatingActionButtonLocation();

//在屏幕上方末端位置原叮,Scaffold.appBar和Scaffold.body之間的過渡上浮動
static const FloatingActionButtonLocation endTop = _EndTopFloatingActionButtonLocation();

drawer 為抽屜 Widget 赫编,通常使用 Drawer ,是一個 StatelessWidget 無狀態(tài) Widget 奋隶,一個由側(cè)邊劃入主界面的 Widget 擂送,其 child 通常是 ListView ,其第一個子級是 DrawerHeader 唯欣,它顯示有關(guān)當(dāng)前用戶的狀態(tài)信息嘹吨。 其余的抽屜式子代通常使用 ListTile 構(gòu)造,通常使用 AboutListTile 結(jié)束境氢。 endDrawerdrawer 一樣蟀拷,只是入口按鈕分別分布在頂部導(dǎo)航的右側(cè)和左側(cè)。其構(gòu)造方法如下:

const Drawer({
  Key key,
  //double類型可選命名參數(shù)萍聊,相對于其上級放置此抽屜的Z坐標(biāo)
  this.elevation = 16.0,
  //Widget類型可選命名參數(shù)问芬,要顯示的Widget
  this.child,
  //String類型可選命名參數(shù),當(dāng)抽屜打開和關(guān)閉時寿桨,輔助功能框架用來宣布屏幕轉(zhuǎn)換的對話框的語義標(biāo)簽
  this.semanticLabel,
})

這里引用官方文檔的例子此衅,展示下效果。關(guān)于 ListView 后面文章會詳細(xì)介紹亭螟,代碼如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyAppTabPage(),
    );;
  }
}

class MyAppTabPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
      ),
      drawer: Drawer(
        child: ListView(
          children: <Widget>[
            DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
              child: Text(
                'Drawer Header',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                ),
              ),
            ),
            ListTile(
              leading: Icon(Icons.message),
              title: Text('Messages'),
            ),
            ListTile(
              leading: Icon(Icons.account_circle),
              title: Text('Profile'),
            ),
            ListTile(
              leading: Icon(Icons.settings),
              title: Text('Settings'),
            ),
          ],
        ),
      ),
      endDrawer: Drawer(),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("點擊");
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

效果如下:

2020312100.jpg

限于篇幅限制挡鞍,下一篇文章將繼續(xù)說明 MaterialAppScaffold 预烙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匕累,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子默伍,更是在濱河造成了極大的恐慌欢嘿,老刑警劉巖衰琐,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異炼蹦,居然都是意外死亡羡宙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門掐隐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狗热,“玉大人,你說我怎么就攤上這事虑省∧涔危” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵探颈,是天一觀的道長熟丸。 經(jīng)常有香客問我,道長伪节,這世上最難降的妖魔是什么光羞? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮怀大,結(jié)果婚禮上纱兑,老公的妹妹穿的比我還像新娘。我一直安慰自己化借,他們只是感情好潜慎,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蓖康,像睡著了一般铐炫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钓瞭,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天驳遵,我揣著相機(jī)與錄音,去河邊找鬼山涡。 笑死堤结,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸭丛。 我是一名探鬼主播竞穷,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鳞溉!你這毒婦竟也來了瘾带?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤熟菲,失蹤者是張志新(化名)和其女友劉穎看政,沒想到半個月后朴恳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡允蚣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年于颖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嚷兔。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡森渐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冒晰,到底是詐尸還是另有隱情同衣,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布壶运,位于F島的核電站耐齐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏前弯。R本人自食惡果不足惜蚪缀,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一秫逝、第九天 我趴在偏房一處隱蔽的房頂上張望恕出。 院中可真熱鬧,春花似錦违帆、人聲如沸浙巫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽的畴。三九已至,卻和暖如春尝胆,著一層夾襖步出監(jiān)牢的瞬間丧裁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工含衔, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留煎娇,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓贪染,卻偏偏與公主長得像缓呛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杭隙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容