Flutter常用的布局和事件示例详解
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, ),
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
上一篇: iOS中你需要的弹窗效果总结大全