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

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,

),

总结

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

以上是 Flutter常用的布局和事件示例详解 的全部内容, 来源链接: utcz.com/p/241726.html

回到顶部