相关文章
Flutter 环境搭建以及填坑指南(Win10 系统且已有 Android 开发环境 )
Flutter 入门实现 ListView 列表页面以及收藏页面
Flutter Widget 静态布局实战
Flutter 容器类 Widget
前面两篇文章介绍了
Flutter win
环境的安装,以及利用listview
实现了简单布局。(这篇文章篇幅有点长,读完大概需要8.88
分钟)
Flutter 入门实现 ListView 列表页面以及收藏页面
Flutter 环境搭建以及填坑指南(Win10 系统且已有 Android 开发环境
这篇文章主要介绍以下内容:
1. ListView 能实现什么效果?
2. widget 如何添加到 ListView 中?
3. ListView 点击事件,单个 widget 点击事件
4. ( 重点 ) widget 如何垂直、水平摆放?
5. 图片、Icon、Text widget 的简单使用
在这篇文章Flutter 入门实现 ListView 列表页面以及收藏页面中虽然实现了一个列表,但是怎么实现的还没仔细研究,现在就先从研究 ListView
的实现开始吧。
先看一下之前实现的效果:
实现的代码主要是RandomWordsState
类中的下面代码:
return new ListTile(
// 单词布局
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
// 喜欢小心心布局
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
// ListView item 的点击事件
onTap: () {
// 通知框架状态已经改变
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
从上面的代码中可以看出实现这个列表主要就是操作了 ListTile
这个 Widget
,那么我们看看这个ListTile
的构造方法都提供了上面功能吧!注释都写在代码中了~
/// Requires one of its ancestors to be a [Material] widget.
const ListTile({
Key key,
// 在列表的左边添加的 widget(如文末图中的左边图片)
this.leading,
// 标题
this.title,
// 副标题
this.subtitle,
// 在列表的右边添加的 widget(如文末图中的右边心形 icon)
this.trailing,
// 如果 isThreeLine 为 true, subtitle 则不能为 null,默认为 false
// 如果 副标题为空则列表平铺一行显示,如果 副标题 不为空,则副标题所占的布局是两行
// 如果 isThreeLine = true 则副标题可以显示三行。
this.isThreeLine = false,
// bool 类型,默认为false ,如果为 true 则 ListTile 在垂直方向是密集型摆放
//(具体效果待后面去实现,这里只是看了注释后的理解)
this.dense,
// 内容的边距
this.contentPadding,
// item 是否能点击
this.enabled = true,
// item 的点击事件
this.onTap,
// item 的长按事件
this.onLongPress,
// item 是否选中标记
this.selected = false,
})
flutter
的开发语言是dart
,这个语言之前没学过,这里就先不深入学习了,网上有比较好的这个博主 恋猫月亮
写的系列的文章写的很好。我这里就只写实现上面图片中展示的效果。
1. ListView 能实现什么效果?
ListView 不仅可以实现列表布局,还可以实现 Android 中的 ScrollView 的功能。关于 滚动的 widget 还有其他的实现,可参考**可滚动Widget简介**
实现列表功能,如果是符合ListTile
的样式,直接使用ListTile
实现很方便。(目前还没学到如何实现多布局,后面学习再写一篇)
实现ScrollView
功能,直接在build
方法的body
中添加我们的 widget
。伪代码如下:
定义了一个
DetailScreen
详情页面,继承了StatelessWidget
,在build
方法中返回了页面的内容:appBar
是标题栏,body
是显示的内容
class DetailScreen extends StatelessWidget {
// Declare a field that holds the pair
final WordPair pair;
// In the constructor, require a pair
DetailScreen({Key key, @required this.pair}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
// 接收传递过来的单词做标题名字
title: new Text("${pair.asPascalCase}"),
),
// 使用 ListView 做滚动列表
body: new ListView(
children: [
// 显示网络图片
new Image.asset(
'images/wali.jpg',
width: 600.0,
height: 240.0,
fit: BoxFit.cover,
),
// 标题行(文末有实现效果)
titleSection,
// 按钮行(文末有实现效果)
buttonSection,
// 描述文本(文末有实现效果)
textSection,
],
),
);
}
}
2. widget 如何添加到 ListView 中?
上面的伪代码中在构建一个有状态的widget
的时候会重写 build
方法,在该方法中的 body
返回我们实现的 widget
即可。
3. ListView 点击事件,单个 widget 点击事件
如果ListView
使用ListTile
实现列表的话,直接使用ListTile
中的 onTap
实现列表点击效果。如果不是用ListTile
实现,那就使用单个widget
的点击事件吧。
widget
的如果有onTap
方法可以直接调用该方法即可实现,如果没有该方法,则需要使用GestureDetector
来实现点击效果,例如上图中的心形喜欢点击事件,伪代码实现如下:
关于
GestureDetector
可参考该文章 手势识别GestureDetector
trailing: new GestureDetector(
// 心形喜欢 icon
child: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
// 点击事件
onTap: (){
// 通知框架状态已经改变
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
),
4. widget 如何垂直、水平摆放?
最常见的布局模式之一是垂直或水平排列widget。在
Flutter
可以使用行Row
水平排列widget
,并使用列Column
垂直排列widget
。 同时,每个孩子本身可以是一个Row
或一个Column
,依此类推。以下示例显示如何在行或列内嵌套行或列。
通过下面两张图片可以学到在实现布局时如何拆分:
参考链接 widget 布局
在控制行或列对齐其子项时使用mainAxisAlignment
( 主轴 ) 和crossAxisAlignment
( 横轴 ) 属性来。 对于行(Row)
来说,**主轴是水平方向,横轴垂直方向。**对于列(Column)
来说,主轴垂直方向,横轴水平方向。
MainAxisAlignment 和CrossAxisAlignment 类提供了很多控制对齐的常量.
MainAxisAlignment
center → const MainAxisAlignment :子
widget
在主轴方向上居中显示end → const MainAxisAlignment :子
widget
在主轴方向上居右边显示,如果是水平方向,那么由 TextDirection 来决定end
是在左边(ltr)还是在右边(rtl)。如果是竖直方向,那么由 VerticalDirection 来决定end
是在上边(up)还是在下边(down)start → const MainAxisAlignment:子
widget
在主轴方向上居左边显示,同理end
。spaceAround → const MainAxisAlignment:子
widget
中的第一个和最后一个widget
距离边的距离是它与中间的距离的一半。(这里比较抽象,后期实现效果了会顺带讲解)spaceBetween → const MainAxisAlignment:子
widget
中的第一个和最后一个贴边,剩余的子widget
将中间的空间平分。spaceEvenly → const MainAxisAlignment:子
widget
将布局空间完全平分values → const List<MainAxisAlignment>:根据值得大小来分配空间,值越大空间分配越多。
CrossAxisAlignment 属性相同的基本和上面介绍的一样,就不赘述了。
- baseline → const CrossAxisAlignment:基线对齐
- center → const CrossAxisAlignment
- end → const CrossAxisAlignment
- start → const CrossAxisAlignment
- stretch → const CrossAxisAlignment:子
widget
填充横轴(CrossAxisAlignment),如果横轴上子widget
很多,会使横轴变得很挤。 - values → const List<CrossAxisAlignment>
Expanded widget
Expanded widget,可以将widget的大小设置为适和行或列
Expanded
有个属性flex(弹性系数)
,默认情况下,每个widget的弹性系数为1,也就是会铺满布局。
例如实现:三张图片水平铺满屏幕,即可使用Expanded
包裹Image
然后设置flex:1
,不设置也行,因为默认flex
就是1
伪代码如下:
body: new Center(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
new Expanded(
child: new Image.asset('images/pic1.jpg'),
),
new Expanded(
child: new Image.asset('images/pic2.jpg'),
),
new Expanded(
child: new Image.asset('images/pic3.jpg'),
),
聚集 widgets
默认情况下,行或列沿着其主轴会尽可能占用尽可能多的空间,但如果要将孩子紧密聚集在一起,可以将
mainAxisSize
设置为MainAxisSize.min
。
例如实现:五个星形图标图标紧凑在一起。
伪代码如下:
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var packedRow = new Row(
mainAxisSize: MainAxisSize.min,
children: [
new Icon(Icons.star, color: Colors.green[500]),
new Icon(Icons.star, color: Colors.green[500]),
new Icon(Icons.star, color: Colors.green[500]),
new Icon(Icons.star, color: Colors.black),
new Icon(Icons.star, color: Colors.black),
],
);
// ...
}
5. 图片、Icon、Text widget 的简单使用
这些都是基础控件使用起来很简单的,可查看这个文档介绍:**基础 Widget**
在学习完上面的内容我们可以实现出目前的样式了:
实现列表功能,以及一个可滚动的详情页面,顶部的标题是 listview 传递过去的单词。
文章篇幅过长了,这里就不介绍上图的实现过程了,源码地址如下
觉得还凑合的给个star
,好让我继续坚持写下去~
源码地址
看源码或者上文中不理解的可以联系我,我会知无不言的。
本文完。
本文同步分享在 博客“_龙衣”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。