当前位置: 移动技术网 > IT编程>移动开发>Android > Flutter常用的布局和事件示例详解

Flutter常用的布局和事件示例详解

2019年07月23日  | 移动技术网IT编程  | 我要评论

对话马云,弃之可惜的上一句,秋田犬

flutter 项目中常用的布局详情,及封装和使用,快速开发项目.

以及手势事件和滚动事件的使用

scaffold 导航栏的实现,有些路由页可能会有抽屉菜单(drawer)以及底部tab导航菜单等

const scaffold({
 key key,
 this.appbar,//标题栏
 this.body,//内容
 this.floatingactionbutton,//悬浮按钮
 this.persistentfooterbuttons,//底部持久化现实按钮
 this.drawer,//侧滑菜单左
 this.enddrawer,//侧滑菜单右
 this.bottomnavigationbar,//底部导航
 this.backgroundcolor,//背景颜色
 this.resizetoavoidbottompadding: true,//自动适应底部padding
 this.primary: true,//使用primary主色
 })

flutter 中自带的material样式的标题栏,首先看一下appbar具有哪些属性,代码如下:

appbar({
 key key,
 this.leading,//主导widget
 this.automaticallyimplyleading: true,
 this.title,//标题
 this.actions,//其他附加功能
 this.flexiblespace,//伸缩空间,显示在title上面
 this.bottom,//显示在title下面
 this.elevation: 4.0,//阴影高度
 this.backgroundcolor,//背景颜色
 this.brightness,//明暗模式
 this.icontheme,//icon主题
 this.texttheme,//text主题
 this.primary: true,//是否是用primary
 this.centertitle,//标题是否居中
 this.titlespacing: navigationtoolbar.kmiddlespacing,//title与leading的间隔
 this.toolbaropacity: 1.0,//title级文字透明度
 this.bottomopacity: 1.0,//底部文字透明度
 })

悬浮button 属性详解

const floatingactionbutton({
 key key,
 this.child,//button的显示样式
 this.tooltip,//提示,长按按钮提示文字
 this.backgroundcolor,//背景颜色
 this.herotag: const _defaultherotag(),//页面切换动画tag
 this.elevation: 6.0,//阴影
 this.highlightelevation: 12.0,//高亮阴影
 @required this.onpressed,//点击事件
 this.mini: false//是否使用小图标
 })

底部导航栏bottomnavigationbar的实现,与经常搭配的pageview实现项目中常用的tab切换

scaffold(
 body: pageview(
 controller: _controller,
 children: <widget>[//page的页面
 homepage(),
 searchpage(),
 travelpage(),
 minepage(),
 ],
 onpagechanged: (int index) {//滑动page的监听
 setstate(() {//改变tab状态
 _controllerindex = index;
 });
 },
 ),
 bottomnavigationbar: bottomnavigationbar(
 currentindex: _controllerindex, //当前的index
 ontap: (index) {//点击tab
 _controller.jumptopage(index); //跳转到具体的页面
 //注意改变_controllerindex的状态
 setstate(() {
 _controllerindex = index;
 });
 },
 type: bottomnavigationbartype.fixed,//固定
 items: [//底部tab图片、字体及颜色
 homeitem(),
 searchitem(),
 travelitem(),
 mineitem(),
 ]),
 );

bottomnavigationbaritem的实现

bottomnavigationbaritem mineitem() {
 return bottomnavigationbaritem(
 icon: icon(
 //定义默认状态下的图片以及颜色
 icons.supervised_user_circle,
 color: _defaultcolor,
 ),
 activeicon: icon(
 //定义选中状态下的图片以及颜色
 icons.supervised_user_circle,
 color: _activitycolor,
 ),
 title: text(
 //定义文字
 '我的',
 style: textstyle(
 color: _controllerindex != 3 ? _defaultcolor : _activitycolor,
 ),
 ));
}

container({
 	key key,
 	this.alignment,//内部widget对齐方式
 this.padding,//内边距
 	color color,//背景颜色,与decoration只能存在一个
 decoration decoration,//背景装饰,与decoration只能存在一个
 this.foregrounddecoration//前景装饰,
 double width,//容器的宽
 	double height,//容器的高
 	boxconstraints constraints//,
 	this.margin,//外边距
 	this.transform,//倾斜
 	this.child,//子widget
})

alignment: 内部widget对齐方式,左上对齐topleft、垂直顶部对齐,水平居中对齐topcenter、右上topright、垂直居中水平左对齐centerleft、居中对齐center、垂直居中水平又对齐centerright、底部左对齐bottomleft、底部居中对齐bottomcenter、底部右对齐bottomright

padding: 内间距,子widget距container的距离。

color: 背景颜色

decoration: 背景装饰

foregrounddecoration: 前景装饰

width:容器的宽

height:容器的高

constraints:容器宽高的约束,容器最终的宽高最终都要受到约束中定义的宽高影响

margin:容器外部的间隔

transform: matrix4变换

child:内部子widget

可以通过decoration装饰器实现圆角和边框,渐变等

decoration: boxdecoration(
 border: border(
 bottom:
 borderside(width: 1, color: color(0xfff2f2f2))), //设置底部分割线
 ),
 borderradius: borderradius.circular(12), //设置圆角
 gradient: lineargradient(
 colors: [
 color(0xffff4e63),
 color(0xffff6cc9),
 ],
 begin: alignment.centerleft,
 end: alignment.centerright,
 ), //
 )

设置网络图片

image.network(
 salesboxmodel.icon,
 fit: boxfit.fill,
 height: 15,
 ),

设置行布局

column({
 key key,
 mainaxisalignment mainaxisalignment = mainaxisalignment.start,//主轴x 排列方式
 mainaxissize mainaxissize = mainaxissize.max,
 crossaxisalignment crossaxisalignment = crossaxisalignment.center,//纵轴排列方式
 textdirection textdirection,
 verticaldirection verticaldirection = verticaldirection.down,
 textbaseline textbaseline,
 list<widget> children = const <widget>[],
 })

设置列布局

row({
 key key,
 mainaxisalignment mainaxisalignment = mainaxisalignment.start,
 mainaxissize mainaxissize = mainaxissize.max,
 crossaxisalignment crossaxisalignment = crossaxisalignment.center,
 textdirection textdirection,
 verticaldirection verticaldirection = verticaldirection.down,
 textbaseline textbaseline,
 list<widget> children = const <widget>[],
 })

设置内边距padding

padding 也是一个widget,它内部可以包裹一个widget

padding(
 padding: edgeinsets.only(top: 10),
 child: text(
 model.title,
 style: textstyle(
 fontsize: 14,
 color: colors.white,
 ),
 ),
 )

设置宽度/高度撑满父布局fractionallysizedbox

fractionallysizedbox({
 key key,
 this.alignment = alignment.center,
 this.widthfactor,//设置为1 则宽度撑满父布局
 this.heightfactor,//设置为1 则高度撑满父布局
 widget child,//包裹的子widget
 })

expanded撑满整个界面

expanded({
 key key,
 int flex = 1,
 @required widget child,
 })

stack 可以理解为栈布局,先放入的显示在最下面,后放入的显示在上面,跟android中的reavitelayout相似

stack({
 key key,
 this.alignment: alignmentdirectional.topstart,//对齐方式
 this.textdirection,
 this.fit: stackfit.loose,//是否按照父类宽高处理自己大小
 this.overflow: overflow.clip,//溢出处理方式
 list<widget> children: const <widget>[],
 })

我们可以用stack来实现:请求网络中的时候,显示加载中的布局;请求网络成功后,隐藏加载中的布局,显示成功的布局.
自定义一个loadingwidget,传递isloading是否正在加载中,child加载成功后显示的布局.这样的好处就是我们可以在任何需要用到加载中的布局时,直接使用,统一管理.使用setstate来改变isloading,来实现状态的改变.

class loadingwidget extends statelesswidget {
 final bool isloading;
 final bool cover;
 final widget child;

 //required必须传递的参数
 const loadingwidget(
 {key key,
 @required this.isloading,
 this.cover = false,
 @required this.child})
 : super(key: key);

 @override
 widget build(buildcontext context) {
 return !cover
 ? !isloading ? child : _loadingview
 : stack(
 children: <widget>[child, isloading ? _loadingview : null],
 );
 }

 widget get _loadingview {
 return center(
 child: circularprogressindicator(), //圆形的进度条
 );
 }
}

看一个简单调用的例子.

class _homepagestate extends state<homepage> {
bool isloading = true;//默认是加载中的状态
 @override
 void initstate() {
 super.initstate();
 _handlerefresh();
 }

 future<null> _handlerefresh() async {
 try {
 homemodel model = await homedao.fetch();
 setstate(() {
 gridnavlist = model.localnavlist;
 girdmodelist = model.gridnav;
 subnavlist = model.subnavlist;
 salesboxmodel = model.salesbox;
 bannerlist = model.bannerlist;
 isloading = false;
 });
 } catch (e) {
 print(e.tostring());
 setstate(() {
 isloading = false;
 });
 }
 return null;
 }
 
 @override
 widget build(buildcontext context) {
 return scaffold(
 backgroundcolor: color(0xfff2f2f2),
 body: loadingwidget(//使用自定义的布局
 isloading: isloading,
 //加载成功后显示的view
 child: stack(
 .......
 )
 )
 );
 }
}

当然,stack还有很多其他的使用场景,可自行翻阅文档stack

indexedstack

只不过indexedstack只显示指定位置的widget,其他的位置的widget不会显示。

pageview 类似android中的viewpage组件,他还可以实现底部导航栏的效果
flutter官网pageview

首先看一下pageview有哪些属性,代码如下:

pageview({
 key key,
 this.scrolldirection = axis.horizontal,
 this.reverse = false,
 pagecontroller controller,
 this.physics,
 this.pagesnapping = true,
 this.onpagechanged,
 list<widget> children = const <widget>[],
 this.dragstartbehavior = dragstartbehavior.down,
 }) : controller = controller ?? _defaultpagecontroller,
 childrendelegate = sliverchildlistdelegate(children),
 super(key: key);

来看一下各个属性的意思

this.scrolldirection = axis.horizontal,axis.vertical//设置滚动方向 横向和竖向

pagesnapping true 带有阻力的滑动,如果设置为false滑动到哪就停止到哪

controller 页面控制器,通过调用jumptopage 实现页面的跳转

bottomnavigationbar

bottomnavigationbar({
 key key,
 @required this.items,
 this.ontap,//点击事件
 this.currentindex = 0,//当前的位置
 bottomnavigationbartype type,//底部固定和隐藏类型
 this.fixedcolor,
 this.iconsize = 24.0,//图片的大小
 })

final list<bottomnavigationbaritem> items;

bottomnavigationbaritem 定义底部的icon 选中的icon 文字

const bottomnavigationbaritem({
 @required this.icon,
 this.title,
 widget activeicon,
 this.backgroundcolor,
 }) : activeicon = activeicon ?? icon,
 assert(icon != null);

底部固定

enum bottomnavigationbartype {
 /// the [bottomnavigationbar]'s [bottomnavigationbaritem]s have fixed width, always
 /// display their text labels, and do not shift when tapped.
 fixed,

 /// the location and size of the [bottomnavigationbar] [bottomnavigationbaritem]s
 /// animate and labels fade in when they are tapped. only the selected item
 /// displays its text label.
 shifting,
}

手势事件gesturedetector

gesturedetector 手势监听,它可以包裹任何widget并处理包裹widget的点击、滑动、双击等事件,gesturedetector extends statelesswidget 可以直接return widget

来看一个widget触发点击事件的例子

gesturedetector(
 ontap: () {
 commonmodel model = bannerlist[index];
 navigator.push(
 context,
 materialpageroute(
 builder: (context) => webview(
 url: model.url,
 title: model.title,
 statusbarcolor: model.statusbarcolor,
 hideappbar: model.hideappbar,
 )));
 },
 child: image.network(bannerlist[index].icon,
 fit: boxfit.fill), //加载网络图片,
 );

另外关于其他的双击、滑动等事件可自行翻阅文档.gesturedetector

滚动事件notificationlistener

notificationlistener 可用于监听所有widget的滚动事件,不管使用何种widget都可以很方便的进行处理

notificationlistener(
 //滚动监听 list view
 onnotification: (scrollnotification) {
 //监听滚动的距离scrollupdatenotification 滚动时在进行回调
 if (scrollnotification is scrollupdatenotification &&
 scrollnotification.depth == 0) {
 //只检测listview的滚动第0个元素widget时候才开始滚动
 _scroll(scrollnotification.metrics.pixels);
 }
 },
 child: _buildlistview,
 ),

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网