本节我们主要通过实现项目中ListView的来巩固练习一下flutter的布局。
下图是我们要实现的效果,仿微信的“发现”页面
图片.png
首先我们来分析一下这个ListView的cell的结构
图片.png
通过这个cell我们把这个view分为左右两个Container
左边Container上面有一个Text和一个Image ,右边Container上面有一个Text和一个红点Image 以及一个箭头。
1.自定义cell
首先我们给cell创建一个类DiscoverCell,然后在类中创建一个构造函数,构造函数的参数有左边Text的文本内容title 左边图标imageName,右边Text的文本内容subTitle,右边‘红点’image图片subImageName,
class DiscoverCell extends StatefulWidget {
final String title;
final String subTitle;
final String imageName;
final String subImageName;
const DiscoverCell({//使用快捷键 option+回车 生成的构造函数
Key key,
@required this.title,
@required this.subTitle,
this.imageName,
this.subImageName
}) : assert(title != null, 'title 不能为空'),//起到断言的作用,当assert()中的条件为true时语句会正常执行
assert(imageName != null, 'imageName 不能为空');
@override
_State createState() => _State();
}
注意:assert()起到断言的作用,当assert()中的条件为true时语句会正常执行,如果条件为false 则会抛出一个异常。
2.cell布局
由于这里cell中的组件都是从左自右水平排列,因此我们这里选择Rrow方式布局左右两个Container。每一个Container中的Text和Image也都是水平排列。所以这里我们用Row里面嵌套Row来布局
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Image(image:AssetImage(widget.imageName),width: 20,height: 20,),
SizedBox(width: 15),
Text(widget.title)
],
),
),
Container(
child: Row(
children: <Widget>[
SizedBox(width: 15),
Text(widget.subTitle != null ? widget.subTitle:'',
style: TextStyle(
color: Colors.grey,
)
),//判断子标题是否为空,不为空则显示
widget.subImageName != null ? Image(image: AssetImage(widget.subImageName),width: 10,height: 10,):Container(),//判断图片是否为空,不为空则显示
Image(image: AssetImage('images/icon_right.png'),width: 20,height: 20,)//右边的箭头图片
],
),
)
],
),
这里稍微讲解一下mainAxisAlignment的几个常用属性
1.spaceEvently
一行中如果有2个widget(五个五角星暂且看成1个widget),那么除去2widget所占据的宽度,3个红色方块宽度是一样的, 如下图所示
2.spaceBetween
一行中如果有2个widget,那么分布2端,如下图所示
3.spaceAround
一行中如果有2个widget,那么每个widget左右都是相同的方块,如下图所示
我们实现效果如图所示:
图片.png
3.ListView中使用
实现了一个cell之后我们到ListView组件中实现多个cell。
child: ListView(
children: <Widget>[
DiscoverCell(title:'朋友圈' ,subTitle: '',imageName: 'images/朋友圈.png',subImageName: ''),
SizedBox(height: 10),//实现cell与cell中高为10的空格
DiscoverCell(title:'扫一扫' ,subTitle: '',imageName: 'images/扫一扫2.png',subImageName: ''),
Row(//实现cell中间的高为1的细线
children: <Widget>[
Container(
color: Colors.white,
width: 15.0,
height: 1,
),
Container(
color: Color.fromRGBO(240, 240, 240, 1)
),
],
),
DiscoverCell(title:'摇一摇' ,subTitle: '',imageName: 'images/摇一摇.png',subImageName: ''),
SizedBox(height: 10),
DiscoverCell(title:'看一看' ,subTitle: '',imageName: 'images/看一看icon.png',subImageName: ''),
Row(
children: <Widget>[
Container(
color: Colors.white,
width: 15.0,
height: 1,
),
Container(
color: Color.fromRGBO(240, 240, 240, 1)
),
],
),
DiscoverCell(title:'搜一搜' ,subTitle: '',imageName: 'images/搜一搜.png',subImageName: ''),
SizedBox(height: 10),
DiscoverCell(title:'附近的人' ,subTitle: '',imageName: 'images/附近的人icon.png',subImageName: ''),
SizedBox(height: 10),
DiscoverCell(title:'购物' ,subTitle: '618限时特惠',imageName: 'images/购物.png',subImageName: 'images/badge.png'),
],
),
这里稍微讲一下SizedBox组件
使用场景
1.一般限制子控件大小
2.还有这么一种场景也可以使用SizeBox,就是可以代替padding和container,然后 用来设置两个控件之间的间距,比如在行或列中就可以设置两个控件之间的间距 主要是可以比使用一个padding或者container简单方便 (在Flutter中可能用不同的控件可以实现到相同的目的,尽量使用越简单的widget来实现)
我们这里用的是第二种使用场景
4.给cell添加点击手势
return GestureDetector(//添加手势组件
onTap:() {
//实现页面跳转路由
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) =>ContactPage()));
setState(() {
_backGroundColors = Colors.white;
});
print('点击了');
},
onTapDown: (TapDownDetails details){//类似于iOS中的selectedState
setState(() {
_backGroundColors = Colors.white30;
});
print('按下来了');
},
}
我们给cell的点击手势里面添加的是跳转到下级页面事件。
至此功能就实现啦。😄
页面效果为:
图片.png
这里吐槽一下pubspec.yaml中设置assets图片路径碰到的小坑,
下面是我在项目中设置的路径的格式,很奇葩的是这个格式居然只能在真机上面加载,在模拟器上加载不出来。
assets:
- images/tabbar_chat.png
- images/tabbar_chat_hl.png
- images/tabbar_friends.png
- images/tabbar_friends_hl.png
- images/tabbar_mine.png
- images/tabbar_mine_hl.png
- images/tabbar_discover.png
- images/tabbar_discover_hl.png
- images/朋友圈.png
- images/icon_right.png
- images/扫一扫2.png
- images/搜一搜.png
- images/摇一摇.png
- images/看一看icon.png
- images/附近的人icon.png
- images/购物.png
- images/badge.png
后面改成了这样:
assets:
- images/tabbar_chat.png
- images/tabbar_chat_hl.png
- images/tabbar_friends.png
- images/tabbar_friends_hl.png
- images/tabbar_mine.png
- images/tabbar_mine_hl.png
- images/tabbar_discover.png
- images/tabbar_discover_hl.png
- images/朋友圈.png
- images/icon_right.png
- images/扫一扫2.png
- images/搜一搜.png
- images/摇一摇.png
- images/看一看icon.png
- images/附近的人icon.png
- images/购物.png
- images/badge.png
即assets:往里面锁进一格,
- images/xxxx往里面缩进两格才成功在模拟器和真机上面都能显示。
参考文章:1.Flutter--SizedBox
2.Flutter MainAxisAlignment.spaceEvently、spaceBetween、spaceAround 区别
3.Flutter 布局(二)- Padding、Align、Center详解
网友评论