- Flutter和Dart系列文章和代碼GitHub地址
-
Flutter
一切皆Widget
的核心思想, 為我們提供了兩種主題風(fēng)格 -
CupertinoApp
: 一個封裝了很多iOS
風(fēng)格的小部件,一般作為頂層widget
使用 -
MaterialApp
: 一個封裝了很多安卓風(fēng)格的小部件践付,一般作為頂層widget
使用, 下面我們先看下這個Widget
MaterialApp
這里我們先看看MaterialApp
的構(gòu)造函數(shù)和相關(guān)函數(shù)
const MaterialApp({
Key key,
// 導(dǎo)航主鍵, GlobalKey<NavigatorState>
this.navigatorKey,
// 主頁, Widget
this.home,
// 路由
this.routes = const <String, WidgetBuilder>{},
// 初始化路由, String
this.initialRoute,
// 構(gòu)造路由, RouteFactory
this.onGenerateRoute,
// 為止路由, RouteFactory
this.onUnknownRoute,
// 導(dǎo)航觀察器
this.navigatorObservers = const <NavigatorObserver>[],
// widget的構(gòu)建
this.builder,
// APP的名字
this.title = '',
// GenerateAppTitle, 每次在WidgetsApp構(gòu)建時都會重新生成
this.onGenerateTitle,
// 背景顏色
this.color,
// 主題, ThemeData
this.theme,
// app語言支持, Locale
this.locale,
// 多語言代理, Iterable<LocalizationsDelegate<dynamic>>
this.localizationsDelegates,
// flutter.widgets.widgetsApp.localeListResolutionCallback
this.localeListResolutionCallback,
// flutter.widgets.widgetsApp.localeResolutionCallback
this.localeResolutionCallback,
// 支持的多語言, Iterable<Locale>
this.supportedLocales = const <Locale>[Locale('en', 'US')],
// 是否顯示網(wǎng)格
this.debugShowMaterialGrid = false,
// 是否打開性能監(jiān)控讯检,覆蓋在屏幕最上面
this.showPerformanceOverlay = false,
// 是否打開柵格緩存圖像的檢查板
this.checkerboardRasterCacheImages = false,
// 是否打開顯示到屏幕外位圖的圖層的檢查面板
this.checkerboardOffscreenLayers = false,
// 是否打開覆蓋圖谋作,顯示框架報告的可訪問性信息 顯示邊框
this.showSemanticsDebugger = false,
// 是否顯示右上角的Debug標(biāo)簽
this.debugShowCheckedModeBanner = true,
})
需要注意的幾點
- 如果
home
首頁指定了寄猩,routes
里面就不能有'/'
的根路由了达皿,會報錯大审,/
指定的根路由就多余了 - 如果沒有
home
指定具體的頁面铃诬,那routes
里面就有/
來指定根路由 - 路由的順序按照下面的規(guī)則來:
- 1祭陷、如果有
home
,就會從home
進(jìn)入 - 2趣席、如果沒有
home
兵志,有routes
,并且routes
指定了入口'/'
吩坝,就會從routes
的/
進(jìn)入 - 3毒姨、如果上面兩個都沒有哑蔫,或者路由達(dá)不到钉寝,如果有
onGenerateRoute
,就會進(jìn)入生成的路由 - 4闸迷、如果連上面的生成路由也沒有嵌纲,就會走到
onUnknownRoute
,不明所以的路由腥沽,比如網(wǎng)絡(luò)連接失敗逮走,可以進(jìn)入斷網(wǎng)的頁面
- 1祭陷、如果有
routes
- 聲明程序中有哪個通過
Navigation.of(context).pushNamed
跳轉(zhuǎn)的路由 - 參數(shù)以鍵值對的形式傳遞
-
key
:路由名字 -
value
:對應(yīng)的Widget
-
routes: {
'/home': (BuildContext content) => Home(),
'/mine': (BuildContext content) => Mine(),
},
initialRoute
- 初始化路由, 當(dāng)用戶進(jìn)入程序時,自動打開對應(yīng)的路由(home還是位于一級)
- 傳入的是上面
routes
的key
, 跳轉(zhuǎn)的是對應(yīng)的Widget
(如果該Widget
有Scaffold.AppBar
,并不做任何修改今阳,左上角有返回鍵)
routes: {
'/home': (BuildContext content) => Home(),
'/mine': (BuildContext content) => Mine(),
},
initialRoute: '/mine',
onGenerateRoute
當(dāng)通過Navigation.of(context).pushNamed
跳轉(zhuǎn)路由時师溅,
在routes
查找不到時茅信,會調(diào)用該方法
onGenerateRoute: (RouteSettings setting) {
return MaterialPageRoute(
settings: setting,
builder: (BuildContext content) => Text('生成一個路由')
);
},
onUnknownRoute
未知路由, 效果跟onGenerateRoute
一樣, 在未設(shè)置onGenerateRoute
的情況下, 才會去調(diào)用onUnknownRoute
onUnknownRoute: (RouteSettings setting) {
return MaterialPageRoute(
settings: setting,
builder: (BuildContext content) => Text('這是一個未知路由')
);
},
navigatorObservers
- 路由觀察器,當(dāng)調(diào)用
Navigator
的相關(guān)方法時墓臭,會回調(diào)相關(guān)的操作 - 比如
push
蘸鲸,pop
,remove
窿锉,replace
是可以拿到當(dāng)前路由和后面路由的信息 - 獲取路由的名字:
route.settings.name
// navigatorObservers: [HomeObserver()],
// 繼承NavigatorObserver
class HomeObserver extends NavigatorObserver {
@override
void didPush(Route route, Route previousRoute) {
super.didPush(route, previousRoute);
// 獲取路由的名字
print('name = ${route.settings.name}');
// 獲取返回的內(nèi)容
print('reaule = ${route.currentResult}');
}
}
builder
如果設(shè)置了這個參數(shù), 那么將會優(yōu)先渲染這個builder
, 而不會在走路由
builder: (BuildContext content, Widget widget) => Text('builder'),
title
- 設(shè)備用于識別用戶的應(yīng)用程序的單行描述
- 在
Android
上酌摇,標(biāo)題顯示在任務(wù)管理器的應(yīng)用程序快照上方,當(dāng)用戶按下“最近的應(yīng)用程序”按鈕時會顯示這些快照 - 在
iOS
上嗡载,無法使用此值窑多。來自應(yīng)用程序的Info.plist
的CFBundleDisplayName
在任何時候都會被引用,否則就會引用CFBundleName
- 要提供初始化的標(biāo)題洼滚,可以用
onGenerateTitle
CupertinoApp
用于創(chuàng)建iOS
風(fēng)格應(yīng)用的頂層組件, 相關(guān)屬性和MaterialApp
相比只是少了theme
和debugShowMaterialGrid
, 其他屬性都一樣, 如下所示
const CupertinoApp({
Key key,
this.navigatorKey,
this.home,
this.routes = const <String, WidgetBuilder>{},
this.initialRoute,
this.onGenerateRoute,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.title = '',
this.onGenerateTitle,
this.color,
this.locale,
this.localizationsDelegates,
this.localeListResolutionCallback,
this.localeResolutionCallback,
this.supportedLocales = const <Locale>[Locale('en', 'US')],
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true,
})
使用示例如下
return CupertinoApp(
title: 'Cupertino App',
color: Colors.red,
home: CupertinoPageScaffold(
backgroundColor: Colors.yellow,
resizeToAvoidBottomInset: true,
navigationBar: CupertinoNavigationBar(
middle: Text('Cupertino App Bar'),
backgroundColor: Colors.blue,
),
child: Center(
child: Container(
child: Text('Hello World'),
),
),
),
);
CupertinoPageScaffold
一個iOS
風(fēng)格的頁面的基本布局結(jié)構(gòu)埂息。包含內(nèi)容和導(dǎo)航欄
const CupertinoPageScaffold({
Key key,
// 設(shè)置導(dǎo)航欄, 后面會詳解
this.navigationBar,
// 設(shè)置內(nèi)容頁面的背景色
this.backgroundColor = CupertinoColors.white,
// 子widget是否應(yīng)該自動調(diào)整自身大小以適應(yīng)底部安全距離
this.resizeToAvoidBottomInset = true,
@required this.child,
})
navigationBar
const CupertinoNavigationBar({
Key key,
//導(dǎo)航欄左側(cè)組件
this.leading,
//是否顯示左邊組件, 好像無效
this.automaticallyImplyLeading = true,
//是否顯示中間組件, 好像無效
this.automaticallyImplyMiddle = true,
//導(dǎo)航欄左側(cè)組件的右邊的文本, 好像無效
this.previousPageTitle,
// 導(dǎo)航欄中間組件
this.middle,
// 導(dǎo)航欄右側(cè)組件
this.backgroundColor = _kDefaultNavBarBackgroundColor,
// 設(shè)置左右組件的內(nèi)邊距, EdgeInsetsDirectional
this.padding,
//左側(cè)默認(rèn)組件和左側(cè)組件右邊文本的顏色
this.actionsForegroundColor = CupertinoColors.activeBlue,
this.transitionBetweenRoutes = true,
this.heroTag = _defaultHeroTag,
})
使用示例
return CupertinoApp(
title: 'Cupertino App',
color: Colors.red,
debugShowCheckedModeBanner: false,
home: CupertinoPageScaffold(
backgroundColor: Colors.yellow,
resizeToAvoidBottomInset: true,
navigationBar: CupertinoNavigationBar(
leading: Icon(Icons.person),
automaticallyImplyLeading: false,
automaticallyImplyMiddle: false,
previousPageTitle: '返回',
middle: Text('Cupertino App Bar'),
trailing: Icon(Icons.money_off),
border: Border.all(),
backgroundColor: Colors.white,
padding: EdgeInsetsDirectional.fromSTEB(10, 10, 10, 10),
actionsForegroundColor: Colors.red,
transitionBetweenRoutes: false,
heroTag: Text('data'),
),
child: Center(
child: Container(
child: Text('Hello World'),
),
),
),
);
Scaffold
-
Scaffold
通常被用作MaterialApp
的子Widget
(安卓風(fēng)格),它會填充可用空間遥巴,占據(jù)整個窗口或設(shè)備屏幕 -
Scaffold
提供了大多數(shù)應(yīng)用程序都應(yīng)該具備的功能耿芹,例如頂部的appBar
,底部的bottomNavigationBar
挪哄,隱藏的側(cè)邊欄drawer
等
const Scaffold({
Key key,
// 顯示在界面頂部的一個AppBar
this.appBar,
// 當(dāng)前界面所顯示的主要內(nèi)容Widget
this.body,
// 懸浮按鈕, 默認(rèn)在右下角位置顯示
this.floatingActionButton,
// 設(shè)置懸浮按鈕的位置
this.floatingActionButtonLocation,
// 懸浮按鈕出現(xiàn)消失的動畫
this.floatingActionButtonAnimator,
// 在底部呈現(xiàn)一組button吧秕,顯示于[bottomNavigationBar]之上,[body]之下
this.persistentFooterButtons,
// 一個垂直面板迹炼,顯示于左側(cè)砸彬,初始處于隱藏狀態(tài)
this.drawer,
// 一個垂直面板,顯示于右側(cè)斯入,初始處于隱藏狀態(tài)
this.endDrawer,
// 出現(xiàn)于底部的一系列水平按鈕
this.bottomNavigationBar,
// 底部的持久化提示框
this.bottomSheet,
// 背景色
this.backgroundColor,
// 重新計算布局空間大小
this.resizeToAvoidBottomPadding = true,
// 是否顯示到底部, 默認(rèn)為true將顯示到頂部狀態(tài)欄
this.primary = true,
})
appBar
設(shè)置導(dǎo)航欄, 接受一個抽象類PreferredSizeWidget
, 這里使用其子類AppBar
進(jìn)行設(shè)置, 后面會詳解
floatingActionButton
- 設(shè)置一個懸浮按鈕, 默認(rèn)在右下角位置顯示, 這里使用
FloatingActionButton
設(shè)置 -
FloatingActionButton
是Material
設(shè)計規(guī)范中的一種特殊Button
砂碉,通常懸浮在頁面的某一個位置作為某種常用動作的快捷入口, 后面會詳解
floatingActionButtonLocation
設(shè)置懸浮按鈕的位置, 接受一個抽象類FloatingActionButtonLocation
// 右下角, 距離底部有一點距離, 默認(rèn)值
static const FloatingActionButtonLocation endFloat = _EndFloatFabLocation();
// 中下方, 距離底部有一點距離
static const FloatingActionButtonLocation centerFloat = _CenterFloatFabLocation();
// 右下角, 距離底部沒有間距
static const FloatingActionButtonLocation endDocked = _EndDockedFloatingActionButtonLocation();
// 中下方, 距離底部沒有間距
static const FloatingActionButtonLocation centerDocked = _CenterDockedFloatingActionButtonLocation();
FloatingActionButton
在Material Design
中,一般用來處理界面中最常用刻两,最基礎(chǔ)的用戶動作增蹭。它一般出現(xiàn)在屏幕內(nèi)容的前面,通常是一個圓形磅摹,中間有一個圖標(biāo), 有以下幾種構(gòu)造函數(shù)
const FloatingActionButton({
Key key,
this.child,
// 文字解釋, 按鈕唄長按時顯示
this.tooltip,
// 前景色
this.foregroundColor,
// 背景色
this.backgroundColor,
// hero效果使用的tag,系統(tǒng)默認(rèn)會給所有FAB使用同一個tag,方便做動畫效果
this.heroTag = const _DefaultHeroTag(),
// 未點擊時陰影值滋迈,默認(rèn)6.0
this.elevation = 6.0,
// 點擊時陰影值,默認(rèn)12.0
this.highlightElevation = 12.0,
// 點擊事件監(jiān)聽
@required this.onPressed,
// 是否為“mini”類型户誓,默認(rèn)為false
this.mini = false,
// 設(shè)置陰影, 設(shè)置shape時饼灿,默認(rèn)的elevation將會失效,默認(rèn)為CircleBorder
this.shape = const CircleBorder(),
// 剪切樣式
this.clipBehavior = Clip.none,
// 設(shè)置點擊區(qū)域大小的樣式, MaterialTapTargetSize的枚舉值
this.materialTapTargetSize,
// 是否為”extended”類型
this.isExtended = false,
})
mini
- 是否為
mini
類型,默認(rèn)為false
-
FloatingActionButton
分為三種類型:regular
,mini
,extended
-
regular
和mini
兩種類型通過默認(rèn)的構(gòu)造方法實現(xiàn), 只有圖片 - 大小限制如下
const BoxConstraints _kSizeConstraints = const BoxConstraints.tightFor(
width: 56.0,
height: 56.0,
);
const BoxConstraints _kMiniSizeConstraints = const BoxConstraints.tightFor(
width: 40.0,
height: 40.0,
);
const BoxConstraints _kExtendedSizeConstraints = const BoxConstraints(
minHeight: 48.0,
maxHeight: 48.0,
);
isExtended
- 是否為
extended
類型, 設(shè)置為true
即可 - 除此之外, 還可以使用
extended
構(gòu)造函數(shù)創(chuàng)建該類型
FloatingActionButton.extended({
Key key,
this.tooltip,
this.foregroundColor,
this.backgroundColor,
this.heroTag = const _DefaultHeroTag(),
this.elevation = 6.0,
this.highlightElevation = 12.0,
@required this.onPressed,
this.shape = const StadiumBorder(),
this.isExtended = true,
this.materialTapTargetSize,
this.clipBehavior = Clip.none,
// 設(shè)置圖片
@required Widget icon,
// 設(shè)置文字
@required Widget label,
})
從參數(shù)上看差異并不大帝美,只是把默認(rèn)構(gòu)造方法中的child
換成了icon
和label
碍彭,不過通過下面的代碼可以看到,傳入的label
和icon
也是用來構(gòu)建child
的,不過使用的是Row
來做一層包裝而已
AppBar
AppBar
是一個Material
風(fēng)格的導(dǎo)航欄庇忌,它可以設(shè)置標(biāo)題舞箍、導(dǎo)航欄菜單、底部Tab
等
AppBar({
Key key,
// 導(dǎo)航欄左側(cè)weidget
this.leading,
// 如果leading為null皆疹,是否自動實現(xiàn)默認(rèn)的leading按鈕
this.automaticallyImplyLeading = true,
// 導(dǎo)航欄標(biāo)題
this.title,
// 導(dǎo)航欄右側(cè)按鈕, 接受一個數(shù)組
this.actions,
// 一個顯示在AppBar下方的控件创译,高度和AppBar高度一樣,可以實現(xiàn)一些特殊的效果墙基,該屬性通常在SliverAppBar中使用
this.flexibleSpace,
// 一個AppBarBottomWidget對象, 設(shè)置TabBar
this.bottom,
//中控件的z坐標(biāo)順序软族,默認(rèn)值為4,對于可滾動的SliverAppBar残制,當(dāng) SliverAppBar和內(nèi)容同級的時候立砸,該值為0,當(dāng)內(nèi)容滾動 SliverAppBar 變?yōu)?Toolbar 的時候初茶,修改elevation的值
this.elevation = 4.0,
// 背景顏色颗祝,默認(rèn)值為 ThemeData.primaryColor。改值通常和下面的三個屬性一起使用
this.backgroundColor,
// 狀態(tài)欄的顏色, 黑白兩種, 取值: Brightness.dark
this.brightness,
// 設(shè)置導(dǎo)航欄上圖標(biāo)的顏色恼布、透明度螺戳、和尺寸信息
this.iconTheme,
// 設(shè)置導(dǎo)航欄上文字樣式
this.textTheme,
// 導(dǎo)航欄的內(nèi)容是否顯示在頂部, 狀態(tài)欄的下面
this.primary = true,
// 標(biāo)題是否居中顯示,默認(rèn)值根據(jù)不同的操作系統(tǒng)折汞,顯示方式不一樣
this.centerTitle,
// 標(biāo)題間距倔幼,如果希望title占用所有可用空間,請將此值設(shè)置為0.0
this.titleSpacing = NavigationToolbar.kMiddleSpacing,
// 應(yīng)用欄的工具欄部分透明度
this.toolbarOpacity = 1.0,
// 底部導(dǎo)航欄的透明度設(shè)置
this.bottomOpacity = 1.0,
})
leading
導(dǎo)航欄左側(cè)weidget
final Widget leading;
// 示例
leading: Icon(Icons.home),
actions
導(dǎo)航欄右側(cè)按鈕, 接受一個數(shù)組
final List<Widget> actions;
// 示例
actions: <Widget>[
Icon(Icons.add),
Icon(Icons.home),
],
brightness
狀態(tài)欄的顏色, 黑白兩種
// 狀態(tài)欄白色
brightness: Brightness.dark,
// 狀態(tài)欄黑色
brightness: Brightness.light,
iconTheme
設(shè)置導(dǎo)航欄上圖標(biāo)的顏色爽待、透明度损同、和尺寸信息
const IconThemeData({this.color, double opacity, this.size})
// 示例
iconTheme: IconThemeData(color: Colors.white, opacity: 0.56, size: 30),
TabBar
- 在
AppBar
中通過bottom
屬性來添加一個導(dǎo)航欄底部tab
按鈕組, 接受一個PreferredSizeWidget
類型 -
PreferredSizeWidget
是一個抽象類, 這里我們使用TabBar
class TabBar extends StatefulWidget implements PreferredSizeWidget {
const TabBar({
Key key,
// 數(shù)組,顯示的標(biāo)簽內(nèi)容,一般使用Tab對象,當(dāng)然也可以是其他的Widget
@required this.tabs,
// TabController對象
this.controller,
// 是否可滾動
this.isScrollable = false,
// 指示器顏色
this.indicatorColor,
// 指示器高度
this.indicatorWeight = 2.0,
// 指示器內(nèi)邊距
this.indicatorPadding = EdgeInsets.zero,
// 設(shè)置選中的樣式decoration,例如邊框等
this.indicator,
// 指示器大小, 枚舉值TabBarIndicatorSize
this.indicatorSize,
// 選中文字顏色
this.labelColor,
// 選中文字樣式
this.labelStyle,
// 文字內(nèi)邊距
this.labelPadding,
// 未選中文字顏色
this.unselectedLabelColor,
// 未選中文字樣式
this.unselectedLabelStyle,
})
}
// Tab的構(gòu)造函數(shù)
const Tab({
Key key,
// 文本
this.text,
// 圖標(biāo)
this.icon,
// 子widget
this.child,
})
效果如下
相關(guān)代碼如下
void main(List<String> args) => runApp(NewApp());
class NewApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return App();
}
}
class App extends State<NewApp> with SingleTickerProviderStateMixin {
List tabs = ['語文', '數(shù)學(xué)', '英語', '政治', '歷史', '地理', '物理', '化學(xué)', '生物'];
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(initialIndex: 0, length: tabs.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('CoderTitan'),
backgroundColor: Colors.blueAccent,
brightness: Brightness.dark,
centerTitle: true,
bottom: TabBar(
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList(),
isScrollable: true,
indicatorColor: Colors.red,
indicatorWeight: 2,
indicatorSize: TabBarIndicatorSize.label,
labelColor: Colors.orange,
unselectedLabelColor: Colors.white,
labelStyle: TextStyle(fontSize: 18, color: Colors.orange),
unselectedLabelStyle: TextStyle(fontSize: 15, color: Colors.white),
),
),
body: TabBarView(
controller: _tabController,
children: tabs.map((e) {
return Container(
alignment: Alignment.center,
child: Text(e, style:TextStyle(fontSize: 50)),
);
}).toList(),
),
),
debugShowCheckedModeBanner: false,
);
}
}
BottomNavigationBar
- 在
Scaffold
中有一個屬性bottomNavigationBar
用于設(shè)置最底部的tabbar
導(dǎo)航欄 - 使用
Material
組件庫提供的BottomNavigationBar
和BottomNavigationBarItem
兩個Widget
來實現(xiàn)Material風(fēng)格的底部導(dǎo)航欄
BottomNavigationBar({
Key key,
// 子widget數(shù)組
@required this.items,
// 每一個item的點擊事件
this.onTap,
// 當(dāng)前選中的索引
this.currentIndex = 0,
// 類型
BottomNavigationBarType type,
// 文字顏色
this.fixedColor,
// 圖片大小
this.iconSize = 24.0,
})
items
包含所有子Widget
的數(shù)組
final List<BottomNavigationBarItem> items;
const BottomNavigationBarItem({
// 未選中圖片
@required this.icon,
// 標(biāo)題
this.title,
// 選中的圖片
Widget activeIcon,
// 背景色
this.backgroundColor,
})
參考文獻(xiàn)
歡迎您掃一掃下面的微信公眾號膏燃,訂閱我的博客!