一、概述
前面幾篇文章介紹了一些基本的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
卵渴、onGeneratedRoute
、builder
在創(chuàng)建 MaterialApp
時,至少有一個必須進(jìn)行設(shè)置纺蛆,不能為 null
字支,否則會報異常欠雌。對于指定應(yīng)用的首界面腌歉,如果在 MaterialApp
提供了 home
馍驯,則使用 home
指定的 Widget 擂煞。如果 home
為 null
蒿涎,則尋找 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è)置的效果如下圖:
現(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(),
),
);;
}
}
效果如下:
AppBar
布局位置如下圖所示:
基本屬性設(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)題
),
),
);;
}
}
效果如下圖:
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,
})
其中 tabs
的 list
使用的 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,
})
TabBar
的 controller
是 TabController
類型番枚。其提供的構(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
是一個動畫控制器,是用來控制和生成動畫的友绝。vsync
為AnimationController.unbounded
構(gòu)造方法的必傳參數(shù)堤尾。vsync
為 TickerProvider
類型,其為抽象類迁客,不能直接使用郭宝,根據(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
,可以使用 TickerProviderStateMixin
和 SingleTickerProviderStateMixin
來獲取一個適合的 TickerProvider
掷漱。
如果在狀態(tài)的聲明周期中有多個 AnimationController
粘室,則使用 TickerProviderStateMixin
。如果只有一個 AnimationController
卜范,則使用 SingleTickerProviderStateMixin
效率更高育特。使用方法為混合該類,然后將 this
設(shè)置給 vsync
即可先朦。官方說明地址為:https://api.flutter.dev/flutter/widgets/SingleTickerProviderStateMixin-mixin.html 缰冤。
使用 TabController
的目的是關(guān)聯(lián) TabBar
和 TabBarView
,TabBarView
是一個頁面視圖喳魏,用于顯示與當(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é)果如下圖:
上面說過,如果在 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,
);
}
}
效果如下圖:
其中 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é)束境氢。 endDrawer
與 drawer
一樣蟀拷,只是入口按鈕分別分布在頂部導(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,
);
}
}
效果如下:
限于篇幅限制挡鞍,下一篇文章將繼續(xù)說明 MaterialApp
、Scaffold
预烙。