Flutter七日遊第四天:2018-12-19 天氣:晴朗
零、前言
最近有些人問我怎麼學的,操作這麼6,有沒有什麼技巧。
今天一開始藉助Image來給大家說一個分析的小技巧,讓你不到30行程式碼畫出下圖
不要問有什麼用,有用的時候自然會用到,有知識儲備,留個印象也是好的
Row和Column應該說是非常常用的控制元件,其中有幾個屬性挺重要,
本文最後,我將對Flex佈局(Row和Column的父類
)進行細緻的講解,希望你不要錯過。
一、第一組控制元件:
1.圖片Image
1.1原始碼一覽:
下面是我從原始碼裡翻譯的,僅供參考
const Image({
Key key,
ImageProvider @required this.image,----圖片提供器
double this.width,----寬
double this.height,----高
Color this.color,----顏色
BoxFit this.fit,----適應模式
colorBlendMode this.colorBlendMode,----顏色混合模式
AlignmentGeometry this.alignment = Alignment.center,----對齊模式
ImageRepeat this.repeat = ImageRepeat.noRepeat,----重複模式
String this.semanticLabel,----語義標籤
bool this.excludeFromSemantics = false,----是否從語義中排除該影像
Rect this.centerSlice,----.9圖的中心區域切片
bool this.matchTextDirection = false,----是否匹配文字分析
bool this.gaplessPlayback = false,----圖片提供器改變
FilterQuality this.filterQuality = FilterQuality.low,---過濾器品質
複製程式碼
1.2:優雅地檢視:圖片的適應模式--BoxFit
也許你為了檢視模式,改一次,看一次,千萬不要這樣,即費時間,比較的效果又差
你需要學會用陣列或map去動態生成,讓變化去應對變化,才能以不變應萬變。
下面的效果呈現,也就用了十幾行程式碼而已,而且準確地表述了BoxFit的各種情況
var fitMode = [BoxFit.none,BoxFit.contain, BoxFit.cover,
BoxFit.fill, BoxFit.fitHeight,BoxFit.fitWidth,BoxFit.scaleDown];
//迴圈生成Image控制元件
formImgs() {
var imgLi = <Widget>[];
fitMode.forEach((fit) {
imgLi.add(Container(
width: 100,
height: 50,
color: randomRGB(),
child: Image(
image: AssetImage("images/wy_200x300.jpg"),
fit: fit,
)));
});
return imgLi;
}
var imgBox = Row(
children: formImgs(),
);
複製程式碼
1.3:優雅地檢視:顏色混合模式--colorBlendMode
暈死---29種疊合模式,Android一共也才18個,Flutter還真會找事...
那麼多情況,Row肯定不夠使,想想昨天的卡片,Wrap能當此大任
//疊合模式陣列
var colorBlendMode = [
BlendMode.clear,BlendMode.src,BlendMode.dst,
BlendMode.srcOver,BlendMode.dstOver,BlendMode.srcIn,
BlendMode.dstIn,BlendMode.srcOut,BlendMode.dstOut,
BlendMode.srcATop,BlendMode.dstATop,BlendMode.xor,
BlendMode.plus, BlendMode.modulate,BlendMode.screen,
BlendMode.overlay,BlendMode.darken,BlendMode.lighten,
BlendMode.colorDodge,BlendMode.colorBurn,BlendMode.hardLight,
BlendMode.softLight,BlendMode.difference,BlendMode.exclusion,
BlendMode.multiply,BlendMode.hue,BlendMode.saturation,
BlendMode.color, BlendMode.luminosity,
];
//迴圈生成Image控制元件
formImgsColorBlendMode() {
var imgLi = <Widget>[];
colorBlendMode.forEach((mode) {
imgLi.add(Column(children: <Widget>[
Padding( child:Image(
width: 60,
height: 60,
image: AssetImage("images/icon_90.png"),
color: Colors.red,
colorBlendMode: mode,
), padding: EdgeInsets.all(5),),
Text(mode.toString().split(".")[1])
]));
});
return imgLi;
}
var imgBox = Wrap(
children: formImgsColorBlendMode(),
);
複製程式碼
一共就這些程式碼,就能實現下面的效果,Android也好,Flutter也好,套路都是一樣的
當你遇到很多種情況的問題時,都可以用這個套路,多分析,你才能鞏固自己的知識庫
重複模式,腦子想想也就知道了,這裡就不演示了
1.4:使用Image的方法載入圖片
這個等到檔案讀取再提一下,基本欄位和Image是一樣的,所以不用擔心。
資源:Image.asset(String name,
檔案:Image.file(File file,
網路:Image.network(String src,
記憶體:Image.memory(Uint8List bytes,
複製程式碼
2.IconButton
2.1原始碼一覽:
const IconButton({
double this.iconSize = 24.0,
EdgeInsetsGeometry this.padding = const EdgeInsets.all(8.0),
AlignmentGeometry this.alignment = Alignment.center,
Widget @required this.icon,
Color this.color,
Color this.highlightColor,
Color this.splashColor,
Color this.disabledColor,
VoidCallback @required this.onPressed,
String this.tooltip
複製程式碼
2.2簡單操作
var iconBtn = IconButton(
padding: EdgeInsets.only(),
onPressed: () {
print("clicked");
},
icon: Icon(Icons.android, size: 40, color: Colors.deepPurpleAccent),
tooltip: "android",
highlightColor: Colors.red,//點選時間稍長的時候背景漸變到這個顏色
splashColor: Colors.blue,//點選時一閃而過的顏色
disabledColor: Colors.blueGrey,
);
複製程式碼
3.ButtonBar
3.1原始碼一覽:
const ButtonBar({
Key key,
this.alignment = MainAxisAlignment.end,
this.mainAxisSize = MainAxisSize.max,
this.children = const <Widget>[],
複製程式碼
3.2簡單操作
var btnBar = ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[iconBtn,iconBtn,iconBtn,iconBtn],
);
複製程式碼
卡片拆包:
- | - | - |
---|---|---|
二、第二組控制元件:
這一組都繼承自MaterialButton,所以屬性幾乎一致,這裡看一下MaterialButton
經歷了這麼多控制元件,屬性基本上都差不多,看到名字也知道大概意思。
const MaterialButton({
@required this.onPressed,----點選事件----VoidCallback
this.onHighlightChanged,
this.textTheme,----按鈕文字主題----ButtonTextTheme
this.textColor,----文字顏色----Color
this.disabledTextColor,----不可用時文字顏色----Color
this.color,----背景顏色----Color
this.disabledColor,----
this.highlightColor,----
this.splashColor,----
this.colorBrightness,
this.elevation,-----陰影高----
this.highlightElevation,
this.disabledElevation,
this.padding,-----內邊距----
this.shape,-----形狀----
this.clipBehavior = Clip.none,
this.materialTapTargetSize,
this.animationDuration,
this.minWidth,
this.height,
this.child,
複製程式碼
1.RaisedButton--凸起的按鈕
RaisedButton和Android的內建Button基本上是一致的
1.1原始碼一覽:
const RaisedButton({
@required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
double elevation,
double highlightElevation,
double disabledElevation,
EdgeInsetsGeometry padding,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
Widget child,
複製程式碼
1.2簡單操作
var raisedButton = RaisedButton(
onPressed: () {},
child: Text("Toly"),
color: Color(0xffF88B0A),
highlightColor: Colors.blue,
);
複製程式碼
2.FlatButton--平的按鈕
FlatButton相當於精簡版的RaisedButton,沒有陰影凸起效果 可見原始碼裡關於elevation都被過濾了
2.1原始碼一覽:
const FlatButton({
Key key,
@required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
EdgeInsetsGeometry padding,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
MaterialTapTargetSize materialTapTargetSize,
@required Widget child,
複製程式碼
2.2簡單操作
var flatButton = FlatButton(
onPressed: () {},
child: Text("Toly"),
color: Color(0xffF88B0A),
highlightColor: Colors.blue,
textColor: Color(0xffFfffff),
);
複製程式碼
3.OutlineButton--框按鈕
OutlineButton是一個框型按鈕
3.1原始碼一覽:
const OutlineButton({
Key key,
@required VoidCallback onPressed,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color highlightColor,
Color splashColor,
double highlightElevation,
this.borderSide,
this.disabledBorderColor,
this.highlightedBorderColor,
EdgeInsetsGeometry padding,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
Widget child,
複製程式碼
3.2簡單操作
var outLineButton = OutlineButton(
onPressed: () {},
child: Text("Toly"),
color: Color(0xffF88B0A),
highlightColor: Colors.blue,
textColor: Color(0xff000000),
borderSide: BorderSide(color: Color(0xff0A66F8), width: 2),
);
複製程式碼
卡片拆包:
- | - | - |
---|---|---|
三、第三組控制元件:
這組效果如下:好像聽到:
汽車人變形,然後AppBar說:我來組成頭部;TabBarView說:我來組成身體,BottomNavigationBar說:我來組成腳部
1.TabBar--標籤Bar
RaisedButton和Android的內建Button基本上是一致的
1.1原始碼一覽:
const TabBar({
Key key,
@required this.tabs,
this.controller,
this.isScrollable = false,
this.indicatorColor,
this.indicatorWeight = 2.0,
this.indicatorPadding = EdgeInsets.zero,
this.indicator,
this.indicatorSize,
this.labelColor,
this.labelStyle,
this.labelPadding,
this.unselectedLabelColor,
this.unselectedLabelStyle,
複製程式碼
1.2:實現方法
var tabBar = TabBar(
labelStyle: TextStyle(fontSize: 20),
labelColor: Color(0xffF64C19),
unselectedLabelColor: Colors.white,
tabs: chartLi.map((item) {
return Container(
alignment: AlignmentDirectional.center,
child: Text(item),
height: 40,
);
}).toList(),
);
//注意一點:主頁的Scaffold標籤要讓DefaultTabController包一下,否則會報錯
home: new DefaultTabController(
child:scaffold,
length: 4))
//並且我將tabBar放在了AppBar的下面,這樣好看一點(當然你可以隨意放)
var scaffold= Scaffold(
appBar: AppBar(
title: Text("張風捷特烈"),
bottom:tabBar,
backgroundColor: Color(0xff54C5F8),
elevation: 12,
centerTitle: true,
toolbarOpacity: .4), //透明度
);
複製程式碼
2.TabBarView
2.1原始碼一覽:
const TabBarView({
Key key,
@required this.children,
this.controller,
this.physics,
複製程式碼
2.2簡單操作
var chartLi = ["About", "Ball", "Card", "Dog"];
var tabBarView = new TabBarView(
children: chartLi.map((text) {
return new Center(
child: new Text(text, style: TextStyle(fontSize: 20),
));
}).toList(),
);
複製程式碼
3.BottomNavigationBar--底部Bar
OutlineButton是一個框型按鈕
3.1原始碼一覽:
BottomNavigationBar({
Key key,
@required this.items,
this.onTap,
this.currentIndex = 0,
BottomNavigationBarType type,
this.fixedColor,
this.iconSize = 24.0,
複製程式碼
3.2簡單操作
var iconInfoMap = {
"首頁": Icon(Icons.home),
"訊息": Icon(Icons.comment),
"動態": Icon(Icons.toys),
"聯絡人": Icon(Icons.contacts),
};
var bottomNavigationBar = BottomNavigationBar(
items: () {
var items = <BottomNavigationBarItem>[];
iconInfoMap.forEach((k, v) {
items.add(BottomNavigationBarItem(
title: Text(k), icon: v, backgroundColor: Color(0xff49B1FB)));
});
return items;
}(),
currentIndex: 1,
onTap: (position) {
print(position);
},
);
//由腳手架將汽車人組合
var scaffold= Scaffold(
appBar: AppBar(title: Text("張風捷特烈"),
bottom:tabBar),
body: tabBarView,
bottomNavigationBar: bottomNavigationBar,
);
複製程式碼
- | - | - |
---|---|---|
第四組:這組有點坑
1.Drawer:我來組成左臂
1.1原始碼一覽:
const Drawer({
Key key,
this.elevation = 16.0,
this.child,
this.semanticLabel,
複製程式碼
1.2:實現方法
var draw = Drawer(
elevation: 5,
child: Container(
alignment: AlignmentDirectional.center,
color: Color(0xff99C6F9),
child: Text(
"張風捷特烈",
style: TextStyle(fontSize: 30),
),
));
//Scaffold組合
var scaffold= Scaffold(
appBar: AppBar(title: Text("張風捷特烈"),
bottom:tabBar),
body: tabBarView,
drawer: draw,
bottomNavigationBar: bottomNavigationBar,
);
複製程式碼
2.SnackBar
2.1原始碼一覽:
const SnackBar({
Key key,
@required this.content,
this.backgroundColor,
this.action,
this.duration = _kSnackBarDisplayDuration,
this.animation,
複製程式碼
2.2簡單操作
var snackBar = SnackBar(
backgroundColor: Color(0xffFB6431),
content: Text('Hello!'),
duration: Duration(seconds: 1),
action: SnackBarAction(
label: '確定',
onPressed: () {
print("張風捷特烈");
}));
//坑點來了,筆記記好---------------
//一開始開啟總是報錯,貌似是context的鍋,百度了一下,已經有人填坑了,
//需要Scaffold的context,而不是我認為的那個context
var scContext;//先宣告一下Scaffold的context
@override
Widget build(BuildContext context) {
var scaffold = Scaffold(
appBar: AppBar(//同前,略...),
//Scaffold的context通過Builder來獲取
body: Builder(builder: (context) {
scContext = context;
return tabBarView;
}),
drawer: draw,
bottomNavigationBar: bottomNavigationBar,
floatingActionButton: FloatingActionButton(
onPressed: () {
Scaffold.of(scContext).showSnackBar(snackBar);//這樣就行了
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
複製程式碼
3.BottomSheet
3.1原始碼一覽:
const BottomSheet({
Key key,
this.animationController,
this.enableDrag = true,
this.elevation = 0.0,
@required this.onClosing,
@required this.builder
複製程式碼
3.2簡單操作
var bottomSheet = BottomSheet(
onClosing: () {},
builder: (context) => (Container(
color: Color(0xffABF5E0),
child:Wrap(
children: <Widget>[
Center(child: Text('絕域從軍計惘然,')),
Center(child: Text('東南幽恨滿詞箋。')),
Center(child: Text('一簫一劍平生意,')),
Center(child: Text('負盡狂名十五年。')),
],
))));
//點選開啟BottomSheet
floatingActionButton: FloatingActionButton(
onPressed: () {
Scaffold.of(scContext).showBottomSheet(bottomSheet.builder);
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
複製程式碼
- | - | - |
---|---|---|
五、第五組
1.TextField:
Flutter版EditText
1.1原始碼一覽:
const TextField({
Key key,
this.controller,----TextEditingController
this.focusNode,
this.decoration = const InputDecoration(),
TextInputType keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.textAlign = TextAlign.start,
this.textDirection,
this.autofocus = false,
this.obscureText = false,
this.autocorrect = true,
this.maxLines = 1,
this.maxLength,
this.maxLengthEnforced = true,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.enableInteractiveSelection = true,
this.onTap,
複製程式碼
1.2:實現方法
var textField = TextField(
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
maxLines: 1,
cursorColor: Colors.black,
cursorWidth: 10,
style: TextStyle(fontSize: 20, color: Colors.lightBlue),
onChanged: (str) {
print(str);
},
onEditingComplete: () {
print("onEditingComplete");
},
onSubmitted: (str) {
print("onSubmitted:" + str);
},
onTap: () {
print("onTap");
},
);
複製程式碼
2.Checkbox:
Flutter版CheckBox
2.1原始碼一覽:
const Checkbox({
Key key,
@required this.value,
this.tristate = false,
@required this.onChanged,
this.activeColor,
this.materialTapTargetSize,
複製程式碼
2.2:實現方法
var checkbox = Checkbox(
value: true,
activeColor: Colors.blue,
onChanged: (value) {
print(value);
},
);
複製程式碼
3.Slider:
3.1原始碼一覽:
const Slider({
@required this.value,
@required this.onChanged,
this.onChangeStart,
this.onChangeEnd,
this.min = 0.0,
this.max = 1.0,
this.divisions,
this.label,
this.activeColor,
this.inactiveColor,
this.semanticFormatterCallback,
複製程式碼
3.2:實現方法
var slider = Slider(
min: 100,
max: 200,
value: 180,
activeColor: Colors.green,
inactiveColor: Colors.grey,
onChanged: (value) {
print(value);
},
onChangeStart: (v) {},
onChangeEnd: (v) {},
);
複製程式碼
- | - | - |
---|---|---|
六、第六組
1.Switch:
1.1原始碼一覽:
const Switch({
Key key,
@required this.value,
@required this.onChanged,
this.activeColor,
this.activeTrackColor,
this.inactiveThumbColor,
this.inactiveTrackColor,
this.activeThumbImage,
this.inactiveThumbImage,
this.materialTapTargetSize,
複製程式碼
1.2:實現方法
var switch_ = Switch(
value: true,
activeColor: Colors.greenAccent,
activeTrackColor: Colors.black,
activeThumbImage: AssetImage("images/icon_90.png"),
onChanged: (bool value) {
print(value);
},
);
複製程式碼
2.Radio:
2.1原始碼一覽:
const Radio({
Key key,
@required this.value,
@required this.groupValue,
@required this.onChanged,
this.activeColor,
this.materialTapTargetSize,
複製程式碼
2.2:實現方法
var numLi = [1, 2, 3, 4, 5, 6, 7];
var radios=Wrap(children: numLi.map((i) {
return Radio<int>(value: i, groupValue: 5, onChanged: (int value) {},);
}).toList());
複製程式碼
3.Chip + CircleAvatar
:
var chip = Chip(
backgroundColor: Color(0xffE5E5E5),
padding: EdgeInsets.all(3),
avatar: CircleAvatar(
backgroundColor: Colors.lightBlue.shade400,
child: new Text(
'Toly',
style: TextStyle(fontSize: 10.0, color: Colors.white),
)),
label: Text('張風捷特烈'),
);
複製程式碼
- | - | - |
---|---|---|
Flutter的控制元件好多啊,常用的差不多也就這樣吧
七、Flex佈局詳解
Flex
是什麼?是Row
和Column
的老爸,現在先忘掉Row
和Column
等你認清Flex怎麼玩的,Row
和Column
也就清楚了
1.先看Flex的的屬性
可以看出direction是必須的,型別和列舉都在下面列出了
有必要普及幾個單詞:mainAxis(主軸) Alignment對齊 CrossAxis主軸的交錯軸
什麼是主軸:direction的方向為主軸,與主軸垂直方向為交錯軸
Flex({
Key key,
@required this.direction,
----Axis.|----horizontal,
|----vertical,
this.mainAxisAlignment = MainAxisAlignment.start,
----MainAxisAlignment.|----start,
|----end,
|----center,
|----spaceBetween,
|----spaceAround,
|----spaceEvenly,
this.mainAxisSize = MainAxisSize.max,
----MainAxisSize.|----max
|----min
this.crossAxisAlignment = CrossAxisAlignment.center,
----CrossAxisAlignment.|----start,
|----end,
|----center,
|----stretch,
|----baseline,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
this.textBaseline,
List<Widget> children = const <Widget>[],
複製程式碼
2.佈局測試1:水平預設狀態
var c1 = Container(width: 50, height: 50, color: Colors.blue);
var c2 = Container(width: 50, height: 80, color: Colors.red);
var c3 = Container(width: 150, height: 50, color: Colors.yellow);
var flex_test = Flex(
direction: Axis.horizontal,
children: <Widget>[c1, c2, c3],
);
複製程式碼
3.水平時主軸的佈局行為:預設:MainAxisAlignment.start
控制屬性:
mainAxisAlignment
4.水平時交錯軸(縱軸)的佈局行為:預設:CrossAxisAlignment.center
5.Flex盒主軸尺寸:mainAxisSize--預設:MainAxisSize.max
就兩個值有啥好怕的,max已經測試完了,就剩一個min了
這min更簡單,主軸方向的Flex盒就等於內容尺寸,而不是外部容器
這就意味著主軸的佈局行為無效,也就像warp_content
如果是主軸水平向的,主軸行為就在水平方向進行,也就是:
Row
如果是主軸縱向的,主軸行為就在豎直方向進行,也就是:Column
6.Expanded與Flex的搭配
Expanded,它能與Flex佈局進行溝通,來讓孩子尺寸變更
我量了一下,如果同時Expanded--c2和c3,最終c2和c3的長度是一樣的
如果同時Expanded--c1,c2和c3,最終c1,c2,c3長度都是一樣的
複製程式碼
好了,今天就是這樣,基本上也就這麼多,明天找幾個經典佈局練練手
後記:捷文規範
1.本文成長記錄及勘誤表
專案原始碼 | 日期 | 備註 |
---|---|---|
V0.1-github | 2018-12-19 | Flutter第4天--基礎控制元件(下)+Flex佈局詳解 |
2.更多關於我
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
我的github | 我的簡書 | 我的掘金 | 個人網站 |
3.宣告
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3----個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援