一、SafeArea
用于在屏幕安全區(qū)中顯示布局。當(dāng)我們沒(méi)有使用Scaffold或未設(shè)置AppBar時(shí),頁(yè)面的布局會(huì)伸展到系統(tǒng)狀態(tài)欄下,如果我們不需要這種沉浸式狀態(tài)欄效果,那么就可以使用SafeArea跳過(guò)狀態(tài)欄區(qū)域(包括底部導(dǎo)航欄)。
用法就是,用SafeArea包裹展示容器
SafeArea(
child: Container()
)
二、顯示與隱藏
- Offstage 具有簡(jiǎn)單的隱藏功能,屬性為true時(shí)表示隱藏,且不占用空間
- Visibility 比Offstage 具有更多功能,visible屬性為false時(shí)表示隱藏
- Opacity 該控件提供透明度的設(shè)置能力,當(dāng)完全透明時(shí),亦可實(shí)現(xiàn)隱藏控件的效果
Visibility 屬性
屬性名 | 類型 | 簡(jiǎn)介 |
---|---|---|
replacement | Widget | 不可見時(shí)顯示的控件,僅當(dāng)maintainState為false時(shí)有效 |
visible | bool | 子控件是否可見 |
maintainState | bool | 不可見時(shí)是否維持狀態(tài) |
maintainAnimation | bool | 不可見時(shí)是否維持子控件動(dòng)畫 |
maintainSize | bool | 不可見時(shí)是否保留空間 |
maintainInteractivity | bool | 不可見時(shí)是否保留交互性 |
Wrap(
children: [
Offstage(offstage: true, child: TextButton(onPressed: (){}, child: const Text('社會(huì)心理學(xué)'))),
Visibility(visible: false, child: TextButton(onPressed: (){}, child: const Text('發(fā)展心理學(xué)'))),
TextButton(onPressed: (){}, child: const Text('變態(tài)心理學(xué)')),
TextButton(onPressed: (){}, child: const Text('健康心理學(xué)')),
TextButton(onPressed: (){}, child: const Text('咨詢心理學(xué)')),
],
),
三、裁剪
- ClipOval 子控件為正方形時(shí)剪裁為內(nèi)切圓,若為矩形時(shí),剪裁為內(nèi)切橢圓
- ClipRRect 將子控件剪裁為圓角矩形
- ClipRect 剪裁溢出部分【?】
- ClipPath 路徑裁剪,可配合CustomClipper實(shí)現(xiàn)各種不規(guī)則效果
除此外,還有一個(gè)控件CircleAvatar也具有類似的功能,但這是一個(gè)視圖控件,而不是功能控件,用于頭像顯示。
//剪裁為內(nèi)切橢圓
ClipOval(
child: Image.asset('assets/img/nezha1.jpeg'),
),
//剪裁為圓角矩形
ClipRRect(borderRadius: BorderRadius.circular(15),child: Image.asset('assets/img/nezha1.jpeg'),),
const SizedBox(height: 10,),
//圓形頭像
const Center(
child: CircleAvatar(
backgroundImage: NetworkImage(
'https://c-ssl.duitang.com/uploads/item/201810/07/20181007131933_qhjkl.thumb.1000_0.jpg'),
maxRadius: 100,
),
),
const SizedBox(height: 10,),
//昵稱頭像
const Center(
child: CircleAvatar(
child: Text('洋哥'),
backgroundColor: Colors.blueAccent,
maxRadius: 30,
),
),
路徑剪裁
ClipPath(
clipper: MyClipper(),
child: Container(
width: 400,
height: 300,
decoration: const BoxDecoration(
color: Color(0xff622F74),
gradient: LinearGradient(
colors: [Colors.red, Colors.yellow],
begin: Alignment.centerRight,
end: Alignment(-1.0, -1.0))),
),
),
class MyClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, 300);
path.lineTo(400, 150);
path.lineTo(400, 0);
path.close();
return path;
}
@override
bool shouldReclip(covariant CustomClipper oldClipper) {
return false;
}
}
四、變換 Transform
Transform可以對(duì)子控件做一系列變換操作。需要注意的是,它的變換是在繪制階段進(jìn)行的,而不是布局(layout)階段,因此無(wú)論對(duì)子控件應(yīng)用何種變換,其占用空間的大小和在屏幕上的位置都是在一開始確定的,不會(huì)變化的。
常用變換
- 平移
- 旋轉(zhuǎn)
- 縮放
- 斜切
Transform控件通常有兩種使用方式,一種使用默認(rèn)構(gòu)造方法,另一種則使用命名構(gòu)造方法。默認(rèn)構(gòu)造方法更強(qiáng)大靈活,命名構(gòu)造方法則更簡(jiǎn)單。
命名構(gòu)造方法如下
- Transform.translate
- Transform.scale
- Taransform.rotate
平移
double dx = 0;
double dy = 0;
Container(
color: Colors.purpleAccent,
child: Transform.translate(offset: Offset(dx, dy),
child: const Text("走么No加油????"),
),
),
TextButton(onPressed: (){
setState(() {
dx++;
dy++;
});
}, child: const Text('點(diǎn)我移動(dòng)')),
TextButton(onPressed: (){
setState(() {
dx--;
dy--;
});
}, child: const Text('點(diǎn)我回位')),
旋轉(zhuǎn)
double PI = 2;
Container(
color: Colors.yellow,
child: Transform.rotate(angle:pi/PI,
child: const Text("看我旋轉(zhuǎn)"),
),
),
TextButton(onPressed: (){
setState(() {
PI++;
});
}, child: const Text('點(diǎn)我旋轉(zhuǎn)')),
TextButton(onPressed: (){
setState(() {
PI--;
});
}, child: const Text('點(diǎn)我旋轉(zhuǎn)')),
使用默認(rèn)構(gòu)造方法時(shí),transform屬性是必傳,此時(shí)需要使用 Matrix4 類作為 4D 矩陣
import 'package:vector_math/vector_math_64.dart' as v;
Container(
color: Colors.blue,
child: Transform(
transform: Matrix4.translation(v.Vector3(5,5,0)),
child: const Text('會(huì)當(dāng)凌絕頂,一覽眾山小'),
),
),
Matrix4 的常用構(gòu)造方法
- scale 縮放
- transform 平移
- rotationZ 繞z軸旋轉(zhuǎn)
- rotationX 繞x軸旋轉(zhuǎn)
- rotationY 繞y軸旋轉(zhuǎn)
- skewX 沿x軸方向斜切
- skewY 沿y軸方向斜切
- skew 沿x、y軸共同矩陣斜切
直接使用Matrix4 的命名構(gòu)造方法還是有些繁瑣,還涉及到導(dǎo)入一些數(shù)學(xué)庫(kù),因此真正推薦的寫法是使用identity構(gòu)造方法來(lái)初始化一個(gè)Matrix4對(duì)象,然后調(diào)用對(duì)應(yīng)的功能方法,示例如下
Container(
color: Colors.pinkAccent,
child: Transform(
transform: Matrix4.identity()
..translate(5.0,5.0,0.0),
child: const Text('會(huì)當(dāng)凌絕頂,一覽眾山小'),
),
),
通過(guò)這種鏈?zhǔn)秸{(diào)用,在后面連續(xù)調(diào)用其他變換方法,可同時(shí)組合多種變換。
需要注意,斜切變換只能使用命名構(gòu)造方法實(shí)現(xiàn)
Container(
color: Colors.lightBlue,
child: Transform(
transform: Matrix4.skewY(-pi/18),
child: const Text('會(huì)當(dāng)凌絕頂,一覽眾山小'),
),
),
注意,除了直接使用Transform控件,還可以通過(guò)設(shè)置Container的transform屬性來(lái)實(shí)現(xiàn)同樣的變換功能,其用法與Transform相同。
五、MediaQuery
MediaQuery主要用于查詢媒體相關(guān)的數(shù)據(jù),使用MediaQuery.of(context)可返回一個(gè)MediaQueryData類型的數(shù)據(jù),通常不會(huì)直接將MediaQuery作為一個(gè)控件使用,但它也可以作為Widget控件樹中的控件使用。
MediaQueryData 的屬性
屬性名 | 類型 | 簡(jiǎn)介 |
---|---|---|
size | Size | 獲取屏幕寬、高。單位為邏輯像素,非物理像素。物理像素 = size*devicePixelRatio |
devicePixelRatio | double | 設(shè)備像素比(密度)。單位邏輯像素對(duì)應(yīng)的物理像素?cái)?shù)量 |
textScaleFactor | double | 單位邏輯像素的字體像素?cái)?shù),若設(shè)為1.5,則放大50% |
platformBrightness | Brightness | 平臺(tái)當(dāng)前亮度模式(iOS夜間模式、安卓9以上支持) |
viewInsets | EdgeInsets | 被系統(tǒng)遮擋的部分,通常指鍵盤。viewInsets.bottom表示鍵盤的高度 |
padding | EdgeInsets | 被系統(tǒng)遮擋的部分,此處指“劉海屏”和安卓底部導(dǎo)航欄高度 |
viewPadding | EdgeInsets | 被系統(tǒng)遮擋的部分,獨(dú)立于padding和viewInsets,通常是全屏 |
systemGestureInsets | EdgeInsets | 沿著屏幕邊緣的區(qū)域,系統(tǒng)在這里消耗某些輸入事件,并阻止將這些事件傳遞給APP。APP應(yīng)避免將手勢(shì)檢測(cè)器定位在系統(tǒng)手勢(shì)識(shí)別的區(qū)域內(nèi) |
physicalDepth | double | 設(shè)備的最大深度(主要在Fuchsia系統(tǒng)上設(shè)置) |
alwaysUse24HourFormat | bool | 是否是24小時(shí)制 |
accessibleNavigation | bool | 否使用TalkBack或VoiceOver等輔助功能與程序進(jìn)行交互 |
invertColors | bool | 是否支持顏色反轉(zhuǎn) |
highContrast | bool | 僅iOS 13以上支持。通過(guò)“設(shè)置”->“輔助功能”->“增加對(duì)比度” |
disableAnimations | bool | 平臺(tái)是否要求盡可能禁用或減少動(dòng)畫 |
boldText | bool | 平臺(tái)是否要求使用粗體 |
orientation | Orientation | 是橫屏還是豎屏 |
需要注意,MediaQuery必須在MaterialApp的作用域下使用,即在MaterialApp控件之后使用。
下面是iPhone 12 mini的模擬器打印數(shù)據(jù)
// 屏幕大小
Size mSize = MediaQuery.of(context).size;
debugPrint(mSize.width.toString()); // 375.0
debugPrint(mSize.height.toString()); // 812.0
// 密度
double mRatio = MediaQuery.of(context).devicePixelRatio;
debugPrint(mRatio.toString()); // 3.0
// 設(shè)備真實(shí)像素
double width = mSize.width * mRatio;
double heigth = mSize.height * mRatio;
debugPrint(width.toString()); // 1125.0
debugPrint(heigth.toString()); // 2436.0
//上下邊距 (狀態(tài)欄 和 內(nèi)置導(dǎo)航鍵)
double topPadding = MediaQuery.of(context).padding.top;
double bottomPadding = MediaQuery.of(context).padding.bottom;
debugPrint(topPadding.toString()); // 50.0
debugPrint(bottomPadding.toString()); // 34.0
六、返回?cái)r截 WillPopScope*
Flutter中可以通過(guò)WillPopScope來(lái)實(shí)現(xiàn)返回按鈕(iOS上的滑動(dòng)返回)攔截。
WillPopScope中的onWillPop屬性是一個(gè)回調(diào)函數(shù),當(dāng)用戶點(diǎn)擊返回按鈕時(shí)會(huì)被調(diào)用(或手勢(shì)操作)。該回調(diào)需要返回一個(gè)Future對(duì)象,如果返回的Future最終值為false時(shí),則當(dāng)前路由不出棧(不會(huì)返回);最終值為true時(shí),當(dāng)前路由出棧退出??梢酝ㄟ^(guò)這個(gè)回調(diào)來(lái)決定是否退出。
WillPopScope(
onWillPop: () async {
if (_lastPressedAt == null ||
DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
//兩次點(diǎn)擊間隔超過(guò)1秒則重新計(jì)時(shí)
_lastPressedAt = DateTime.now();
return false;
}
return true;
},
child: Container(
alignment: Alignment.center,
child: Text("1秒內(nèi)連續(xù)點(diǎn)擊兩次返回鍵才退出"),
)
);
七、Builder
使用一個(gè)閉包來(lái)創(chuàng)建Widget。它的主要用途有兩個(gè)
獲取某個(gè)控件中的上下文對(duì)象(BuildContext)
使用一個(gè)函數(shù)來(lái)構(gòu)建Widget,這樣可以在構(gòu)建前做一些初始化操作
// 以下局部主題修改不生效,則需要使用Builder獲取正確的上下文對(duì)象。
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.orange,
primaryColor: Colors.orange,
),
home: Scaffold(
appBar: AppBar(
title: Text(
"Flutter",
style: TextStyle(color: Theme.of(context).accentColor),
),
),
body: Container(
alignment: Alignment.center,
child: Theme(
data: Theme.of(context).copyWith(primaryColor: Colors.red),
child: Text(
"測(cè)試",
style: TextStyle(color: Theme.of(context).primaryColor),
),
),
),
),
);
八、模糊處理 BackdropFilter
該控件主要用于模糊處理,它不僅可以處理圖片,也可以處理任意的其他控件。但通常不建議使用模糊處理,對(duì)渲染性能影響很大。
模糊圖層使用 ImageFilter.blur 設(shè)置模糊度,一般是在 0.0-10.0 之間,數(shù)值越大模糊度越高,超過(guò) 10.0 時(shí)完全不可見。另外蒙層還需要設(shè)置一個(gè)色值,通??墒褂?withOpacity 方法設(shè)置透明度,一般是在 0.0-1.0 之間。
Stack(
alignment: Alignment.center,
children: <Widget>[
SizedBox(
width: 300,
height: 400,
child: Image.network('https://c-ssl.duitang.com/uploads/item/201810/07/20181007131933_qhjkl.thumb.1000_0.jpg'),
),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 2.0,sigmaY: 1.0),
child: Center(
child: Container(
height: 200,
width: 100,
color: Colors.red.withOpacity(0),
),
),
)
],
),
九、截圖 RepaintBoundary*
可用于截取當(dāng)前屏幕的Widget的截圖,只需要套在想要截圖的控件的外層。如要獲取全屏截圖,將RepaintBoundary包裹在最外層即可。
十、主題 Theme
Theme 控件為Material APP 定義了主題數(shù)據(jù)(ThemeData)。在Flutter 中已預(yù)定義了一系列的主題,許多控件或部分或全部應(yīng)用了這些主題,因此當(dāng)更改了預(yù)定義主題后,所有使用了這些主題的Widget也都會(huì)發(fā)生相應(yīng)的變化。
Theme 主要描述了應(yīng)用程序的顏色和排版選擇。主題分為兩種:
- 全局 Theme 是由應(yīng)用程序根MaterialApp創(chuàng)建的主題
MaterialApp(
title: title,
theme: ThemeData(
primaryColor: Colors.red,
///...
),
);
- 局部 Theme 在應(yīng)用程序某個(gè)區(qū)域范圍中用于覆蓋全局主題,實(shí)現(xiàn)靈活的差異化
// 對(duì)于修改主題的控件,使用Theme包裹
Theme(
data: ThemeData(
accentColor: Colors.yellow,
//...
),
child: Text('Hello World'),
);
如需獲取主題,可使用如下方式
Container(
color: Theme.of(context).accentColor,
chile: Text(
'Text with a background color',
style: Theme.of(context).textTheme.title,
),
);
有時(shí)候我們不想要覆蓋所有的主題屬性,這時(shí)候可以擴(kuò)展父主題
Theme(
/// 使用 copyWith 找到并擴(kuò)展父主題
data: Theme.of(context).copyWith(accentColor: Colors.yellow),
child: FloatingActionButton(
onPressed: null,
child: Icon(Icons.add),
),
);
Flutter 中主要通過(guò)ThemeData去保存應(yīng)用的主題及樣式等信息,因此需要重點(diǎn)了解該類的屬性。
屬性名 | 類型 | 簡(jiǎn)介 |
---|---|---|
brightness | Brightness | 應(yīng)用的整體主題亮度(可用于適配夜間模式) |
primarySwatch | MaterialColor | Material 定義的主題顏色樣本。它是具有十種顏色陰影的顏色樣本 |
primaryColor | Color | 主色,決定導(dǎo)航欄顏色 |
primaryColorBrightness | Brightness | primaryColor的亮度 |
primaryColorLight | Color | primaryColor的較淺版本 |
primaryColorDark | Color | primaryColor的較深版本 |
accentColor | Color | 小控件的前景色(按鈕、文本、覆蓋邊緣效果等) |
accentColorBrightness | Brightness | accentColor的亮度 |
canvasColor | Color | MaterialType.canvas 的默認(rèn)顏色 |
scaffoldBackgroundColor | Color | 為Scaffold下的Material默認(rèn)色,用于app的背景色 |
bottomAppBarColor | Color | bottomAppBarColor的默認(rèn)顏色 |
cardColor | Color | 用在卡片(Card)上的Material的顏色 |
dividerColor | Color | Divider和PopupMenuDivider的顏色,也用于ListTile之間、DataTable的行之間等 |
highlightColor | Color | 用于濺墨動(dòng)畫或指示菜單被選中時(shí)的高亮顏色 |
splashColor | Color | 濺墨效果顏色(水波紋) |
splashFactory | InteractiveInkFeatureFactory | 定義InkWall和InkResponse的外觀 |
selectedRowColor | Color | 高亮選定行的顏色 |
unselectedWidgetColor | Color | 用于處于非活動(dòng)(但已啟用)狀態(tài)的小控件的顏色。例如未選中的復(fù)選框 |
disabledColor | Color | 禁用狀態(tài)下小控件的顏色 |
buttonColor | Color | RaisedButtons使用的默認(rèn)填充色 |
buttonTheme | ButtonThemeData | 定義按鈕部件的默認(rèn)配置 |
secondaryHeaderColor | Color | 選定行時(shí)PaginatedDataTable標(biāo)題的顏色 |
textSelectionColor | Color | 文本框(如TextField)中文本被選中的顏色 |
cursorColor | Color | 文本框中光標(biāo)的顏色 |
textSelectionHandleColor | Color | 用于調(diào)整當(dāng)前選定文本部分的句柄的顏色 |
backgroundColor | Color | 與primaryColor形成對(duì)比的顏色,例如用作進(jìn)度條的剩余部分 |
dialogBackgroundColor | Color | Dialog的背景色 |
indicatorColor | Color | TabBar中選中的指示器顏色 |
hintColor | Color | 用于提示文本或占位符文本的顏色,例如在TextField中 |
errorColor | Color | 用于輸入驗(yàn)證錯(cuò)誤的顏色,例如在TextField中 |
toggleableActiveColor | Color | 用于突出顯示Switch、Radio和Checkbox等可切換小部件的活動(dòng)狀態(tài)的顏色 |
fontFamily | String | 字體類型 |
textTheme | TextTheme | 與卡片和畫布對(duì)比的文本顏色 |
primaryTextTheme | TextTheme | 與primaryColor形成對(duì)比的文本主題 |
accentTextTheme | TextTheme | 與accentColor形成對(duì)比的文本主題 |
inputDecorationTheme | InputDecorationTheme | InputDecorator、TextField和TextFormField的默認(rèn)InputDecoration值基于此主題 |
iconTheme | IconThemeData | 與卡片和畫布顏色形成對(duì)比的圖標(biāo)主題 |
primaryIconTheme | IconThemeData | 與primaryColor形成對(duì)比的圖標(biāo)主題 |
accentIconTheme | IconThemeData | 與accentColor形成對(duì)比的圖標(biāo)主題 |
sliderTheme | SliderThemeData | 用于呈現(xiàn)Slider的顏色和形狀 |
tabBarTheme | TabBarTheme | 用于自定義選項(xiàng)卡指示器的大小、形狀和顏色的主題 |
cardTheme | CardTheme | Card的顏色和樣式 |
chipTheme | ChipThemeData | Chip的顏色和樣式 |
platform | TargetPlatform | 小控件應(yīng)該適應(yīng)目標(biāo)的平臺(tái),應(yīng)該被用來(lái)根據(jù)平臺(tái)的約定來(lái)樣式化UI元素 |
materialTapTargetSize | MaterialTapTargetSize | 配置某些Material部件的命中測(cè)試大小 |
pageTransitionsTheme | PageTransitionsTheme | 每個(gè)目標(biāo)平臺(tái)的默認(rèn)MaterialPageRoute轉(zhuǎn)換 |
appBarTheme | AppBarTheme | 用于自定義Appbar的顏色、高度、亮度、iconTheme和textTheme的主題 |
bottomAppBarTheme | BottomAppBarTheme | 自定義BottomAppBar的形狀、高度和顏色的主題 |
colorScheme | ColorScheme | 一組13種顏色,可用于配置大多數(shù)組件的顏色屬性 |
dialogTheme | DialogTheme | 自定義Dialog的主題形狀 |
typography | Typography | 用于配置TextTheme、primaryTextTheme和accentTextTheme的顏色和幾何文本主題值 |
cupertinoOverrideTheme | CupertinoThemeData | 用來(lái)覆蓋Cupertino主題的樣式 |
/// 判斷當(dāng)前是否是夜間模式
bool isDarkMode(BuildContext context){
return Theme.of(context).brightness == Brightness.dark;
}
十一、異步 UI*
1.FutureBuilder
2.StreamBuilder