项目演示github地址
Flutter 的界面基本由Widgets组成,widget需要位于MaterialApp内才能正常显示。
Flutter提供了许多widgets,可帮助您构建遵循Material Design的应用程序。
Material应用程序以MaterialApp widget开始, 该widget在应用程序的根部创建了一些有用的widget,其中包括一个Navigator, 它管理由字符串标识的Widget栈(即页面路由栈)。可以让您的应用程序在页面之间的平滑的过渡。 是否使用MaterialApp完全是可选的,但是使用它是一个很好的做法。
应用程序继承了 StatelessWidget,这将会使应用本身也成为一个widget。 在Flutter中,大多数东西都是widget,包括对齐(alignment)、填充(padding)和布局(layout)
Scaffold 是 Material library 中提供的一个widget, 它提供了默认的导航栏、标题和包含主屏幕widget树的body属性。widget树可以很复杂。
Flutter有一套丰富、强大的基础widget,其中以下是很常用的:
- Text该 widget 可让创建一个带格式的文本。
设置文字&文字大小&颜色&行数限制&文本对齐
const Text( "hello flutter!",
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis, // 溢出显示。。。
style: TextStyle(fontSize: 30.0,// 文字大小
color: Colors.yellow),// 文字颜色
),
- Row 、Column 这些具有弹性空间的布局类Widget可让您在水平(Row)和垂直(Column)方向上创建灵活的布局。其设计是基于web开发中的Flexbox布局模型。
//水平布局
Widget buildColumns() {
Row column = new Row(
children: [
new Text('hello'),
new Icon(Icons.mail),
],
);
return column;
}
//垂直布局
Widget buildColumns1() {
Column column = new Column(
children: [
new Icon(Icons.info),
new Icon(Icons.mail),
],
);
return column;
}
Stack
: 取代线性布局 (译者语:和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用Positioned
来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝度定位(absolute positioning )布局模型设计的。Container
: Container可让您创建矩形视觉元素。container 可以装饰为一个BoxDecoration
,
Flutter的设计思想就是完全的widget化。这也就是说连最基本的padding,Center都是widget。设想一下如果每次写view,连padding,Center都要自己包一个组件是一种怎样的体验?作为一个工程师,别给只给我谈思想,实际操作的操作效率也同样非常重要。flutter 官方也意识到了这个问题,他们从实际编写效率的角提供了一个友好高效的封装,这就是Container!首先没有任何疑问,Container 本身也是一个widget。但是他却提供了对基础widget的封装,提高了UI基础装饰能力的表达效率。Container类似于android中的ViewGroup。
它是一个组合的widget,内部有绘制widget、定位widget、尺寸widget。后续看到的不少widget,都是通过一些更基础的widget组合而成的。
Container的组成如下:Container参考文章
最里层的是child元素;
child元素首先会被padding包着;
然后添加额外的constraints限制;
最后添加margin。
Container的绘制的过程如下:
首先会绘制transform效果;
接着绘制decoration;
然后绘制child;
最后绘制foregroundDecoration。
- 装饰
Decoration是对Container进行装饰的描述。其概念类似与android中的shape。一般实际场景中会使用他的子类BoxDecoration。BoxDecoration提供了对背景色,边框,圆角,阴影和渐变等功能的定制能力。
需要注意几个点:
BoxDecoration的image属性相当于设置的是背景图。但是image会绘制在color 和gradient之上。
image是需要一个DecorationImage类的实现。DecorationImage的属性和Image组件比较类似,可以复用Image组件中的ImageProvider。
- 大小
BoxConstraints其实是对Container组件大小的描述。BoxConstraints属性比较简单。如果不太清楚可以研究一下盒子模型。这里有个点需要重点说明一下:
如何表达尽可能大这样的意思?(类似于android中的match_parent)Flutter中可以使用double.infinity来做出类似的表达。
- 实践Coding
设置边框&padding&margin&圆角&背景图
new Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(15.0),
margin: const EdgeInsets.all(15.0),
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.red,
),
image: const DecorationImage(
image: const NetworkImage(
'https://gw.alicdn.com/tfs/TB1CgtkJeuSBuNjy1XcXXcYjFXa-906-520.png',
),
fit: BoxFit.contain,
),
//borderRadius: const BorderRadius.all(const Radius.circular(6.0)),
borderRadius: const BorderRadius.only(
topLeft: const Radius.circular(3.0),
topRight: const Radius.circular(6.0),
bottomLeft: const Radius.circular(9.0),
bottomRight: const Radius.circular(0.0),
),
),
child: Text(''),
),
Scaffold是Material中主要的布局组件,现在来看看Scaffold的几个重要属性:
1、appBar
appBar显示在Scaffold的顶部。
appBar: new AppBar(
title: new Text('Scaffold Widget Demo'),
centerTitle: true,
backgroundColor: Colors.red,
),
centerTitle:让文本居中显示。默认是居左显示
backgroundColor:导航栏背景颜色
2、backgroundColor 这个是整个Scaffold的背景颜色
3、body 主要内容的视图区域,在这个里面,展示的是你的核心内容
4、bottomNavigationBar 用于显示底部导航栏
5、floatingActionButton 浮动于body右上角的按钮
6、floatingActionButtonLocation 决定floatingActionButton按钮的位置
stack
在实际开发中,还是需要在一些Widgets的上面再覆盖上新的Widgets。这时候就需要层式布局了。这种布局在Native上,以android为例,类似于relativeLayout 或者FrameLayout。在Flutter中使用的是Stack。
实际使用中Stack中的子Widgets分为两种:
positioned
是包裹在组件Positioned中的组件
可以通过Positioned属性灵活定位
non-positioned
没有包裹在Positioned组件中
需要通过父Widget Stack 的属性来控制布局
对于non-positioned children, 我们通过控制Stack的alignment属性来控制对齐方式。Positioned的布局方式类似于H5&weex中的position布局中的absolute布局方式。通过设置距离父组件上下左右的距离,Positioned对象能在Stack布局中更加灵活的控制view的展现方式。
层叠布局
new Container(
color: Colors.yellow,
height: 150.0,
width: 500.0,
child: new Stack(children: [
new Container(
color: Colors.blueAccent,
height: 50.0,
width: 100.0,
alignment: Alignment.center,
child: Text('unPositioned'),
),
new Positioned(
left: 40.0,
top: 80.0,
child: new Container(
color: Colors.pink,
height: 50.0,
width: 95.0,
alignment: Alignment.center,
child: Text('Positioned'),
)),
]))
Visibility
当你看完Flutter Widge文档的时候,我们突然发现一个略显尴尬的问题:组件是否显示怎么控制?貌似所有的组件中都没有这个属性!这不坑了,咋办?
目前看方法无非如下几个:
- 删除法
核心将该真实widget或者widget树从renderTree中移除。
具体到实践级别主要分为两个:
单个组件‘隐藏’自己。在build方法中返回一个空的Container.
@override
Widget build(BuildContext context) {
return isVisible
? Widget //真的Widget
: new Container(); //空Widget 仅仅占位 并不显示
}
多个child
在父容器的children字段的list中,删除掉对应的cell。
- Offstage
Offstage 是一个widget。Offstage的offstage属性设置为true,那么Offstage以及他的child都将不会被绘制到界面上。
sample code如下:
@override
Widget build(BuildContext context) {
return new Offstage(
offstage: !isVisible,
child:child);
}
- 透明度
设置widget的透明度,使之不可见。但是这样的方法是副作用的。因为这个对应的widget树是已经经过了完整的layout&paint过程,成本高。同时设置透明度本身也要耗费一定的计算资源,造成了二次浪费。需要注意的是即便变透明了,占据的位置还在。大家慎重选择使用。
sample code如下:
@override
Widget build(BuildContext context) {
return new AnimatedOpacity(
duration: Duration(milliseconds: 10),
opacity: isVisible ? 1.0 : 0.0,
child:child);
}
visibility的控制还是比较麻烦的。这是Flutter设计上不符合正常习惯的一个点,需要大家重点关注。
参考链接