Flutter七日游第四天:2018-12-19 天气:晴朗
零、前言
图片的颜色混合模式.png最近有些人问我怎么学的,操作这么6,有没有什么技巧。
今天一开始借助Image来给大家说一个分析的小技巧,让你不到30行代码画出下图
不要问有什么用,有用的时候自然会用到,有知识储备,留个印象也是好的
Row和Column应该说是非常常用的控件,其中有几个属性挺重要,
本文最后,我将对Flex布局(Row和Column的父类
)进行细致的讲解,希望你不要错过。
一、第一组控件:
第一组.png1.图片Image
图片的使用.png1.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
图片的适应模式.png也许你为了查看模式,改一次,看一次,千万不要这样,即费时间,比较的效果又差
你需要学会用数组或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(),
);
图片的颜色混合模式.png一共就这些代码,就能实现下面的效果,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简单操作
IconButton.gifvar 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简单操作
BottonBar使用.pngvar btnBar = ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[iconBtn,iconBtn,iconBtn,iconBtn],
);
卡片拆包:
- | - | - |
---|---|---|
二、第二组控件:
第二组.png这一组都继承自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简单操作
RaisedButtonvar 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简单操作
FlatButton.gifvar 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简单操作
OutlineButton.gifvar outLineButton = OutlineButton(
onPressed: () {},
child: Text("Toly"),
color: Color(0xffF88B0A),
highlightColor: Colors.blue,
textColor: Color(0xff000000),
borderSide: BorderSide(color: Color(0xff0A66F8), width: 2),
);
卡片拆包:
- | - | - |
---|---|---|
三、第三组控件:
第三组.png这组效果如下:好像听到:
汽车人变形,然后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:实现方法
TabBar测试.pngvar 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简单操作
底栏.pngvar 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,
);
- | - | - |
---|---|---|
第四组:这组有点坑
第四组.png1.Drawer:我来组成左臂
1.1源码一览:
const Drawer({
Key key,
this.elevation = 16.0,
this.child,
this.semanticLabel,
1.2:实现方法
drawer.gifvar 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简单操作
SnackBar.gifvar 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简单操作
BottomSheet.gifvar 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),
),
- | - | - |
---|---|---|
五、第五组
第五组.png1.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:实现方法
TextField测试.pngvar 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:实现方法
Checkbox.pngvar 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:实现方法
Slider.pngvar slider = Slider(
min: 100,
max: 200,
value: 180,
activeColor: Colors.green,
inactiveColor: Colors.grey,
onChanged: (value) {
print(value);
},
onChangeStart: (v) {},
onChangeEnd: (v) {},
);
- | - | - |
---|---|---|
六、第六组
第六组.png1.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:实现方法
Switch.pngvar 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:实现方法
Radio测试.pngvar 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
:
Chip + CircleAvatar.png
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:水平默认状态
水平默认状态.pngvar 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
水平时主轴的布局行为.png控制属性:
mainAxisAlignment
4.水平时交错轴(纵轴)的布局行为:默认:CrossAxisAlignment.center
水平时交错轴的布局行为.png
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长度都是一样的
expaned.png
好了,今天就是这样,基本上也就这么多,明天找几个经典布局练练手
后记:捷文规范
1.本文成长记录及勘误表
项目源码 | 日期 | 备注 |
---|---|---|
V0.1-github | 2018-12-19 | Flutter第4天--基础控件(下)+Flex布局详解 |
2.更多关于我
笔名 | 微信 | 爱好 | |
---|---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 | 语言 |
我的github | 我的简书 | 我的掘金 | 个人网站 |
3.声明
1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持
icon_wx_200.png
网友评论