用Flutter实现小Q聊天机器人(一)
用Flutter实现小Q聊天机器人(二)
用Flutter实现小Q聊天机器人(三)
用Flutter实现小Q聊天机器人(四)
用Flutter实现小Q聊天机器人(五)
GitHub:https://github.com/baiyuliang/Qrobot_Flutter
上一篇,我们实现了一个文本+输入框的垂直排列布局,那么本篇,我们来学习如何实现一个Listview;
依然用最简单的代码实现:
class _MyHomePageState extends State<MyHomePage> {
var imageModellList = List<ImageModel>();
@override
void initState() {
super.initState();
for (var i = 0; i < 20; i++) {
imageModellList.add(ImageModel("标题$i",
"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2602558426,100251765&fm=27&gp=0.jpg"));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemBuilder: (context, index) {
return Column(children: <Widget>[
Text(imageModellList[index].title),
Image.network(imageModellList[index].url)
]);
},
itemCount: imageModellList.length,
));
}
}
首先在_MyHomePageState 类中声明一个变量:imageModellList,用于存放列表Item的对象,然后初始化方法中去添加一些用于测试的数据,初始化方法initState,顾名思义,在进行一些初始化操作时可以在该方法中进行,我们这里手动的给list添加了20条测试对象;
如何定义类及引用类:
ImageModel:
class ImageModel{
var title;
var url;
ImageModel(title,url){
this.title=title;
this.url=url;
}
}
跟java太像了,像的我都不想再做过多说明了,需要了解的是,java中文件名必须与类名像同,但dart却不需要,
使用该类的时候只需要在需要引用的文件中import即可:
import 'image_model.dart';
然后我们来说ListView,创建ListView组件时要用到builder方法,属性itemBuilder两个参数(context,index)上下文和item的position,其返回的就是item的布局view,itemCount即ListView的item的数量,这里需要注意的是dart中的list的item不能像java中通过list.get()获取,而是通过list[i]获取,长度用list.length表示而不是list.size(),声明完数据,再布局完itemView并完成绑定,listview就可以显示出来了,是不是很简单?
对于如何加载网络图片,只需要用Image的network方法就可以了,Image还有其它更多方法提供:
根据不同需求选择不同方法!
我们继续来看,这个ListView虽然实现了,但是界面太丑了,我想控制Text的大小、颜色、边距,图片的宽高,裁剪方式等,该如何做呢?别急我们一点一点来实现!
首先Text的大小颜色等属性需要用到TextStyle类,具体写法如下:
style: TextStyle(fontSize: 15,color: Colors.blue),
但由于Text组件本身不具备设置margin及padding属性,那么我们就需要在Text外层套一个Container来设置margin或padding,Container上面说过,可以理解为一个ViewGroup或者h5中的div,代码如下:
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: Text(
imageModellList[index].title,
style: TextStyle(fontSize: 15, color: Colors.blue),
),
),
Image.network(imageModellList[index].url)
]);
}
运行效果:
EdgeInsets边距设置的一个类,margin和padding都可以使用,EdgeInsets.all(10)表示上下左右边距全部为10,EdgeInsets.only()则可以单独设置某一方向的边距,例如:EdgeInsets.only(left:10,right:10);
那么我现在还是不满意,想把标题左对齐,然后给图片也加个边距,该如何做呢?
首先,Column和Row默认子组件都是居中的,所以如果想设置子组件的对齐方式,则需要用到两个类和属性:MainAxisAlignment和CrossAxisAlignment,对应的属性为:mainAxisAlignment和crossAxisAlignmentc;
- mainAxisAlignment:主轴布局方式,column主轴方向是垂直的方向:
- start ,沿着主轴方向(垂直方向)顶部对齐;
- end,沿着主轴方向(垂直方向)底部对齐;
- center,沿着主轴方向(垂直方向)居中对齐;
- spaceBetween ,沿着主轴方向(垂直方向)平分剩余空间;
- spaceAround,把剩余空间平分成n份,n是子widget的数量,然后把其中一份空间分成2份,放在第一个child的前面,和最后一个child的后面;
- spaceEvenly,把剩余空间平分n+1份,然后平分所有的空间,请注意和spaceAround的区别;
- crossAxisAlignment: 交叉轴的布局方式,对于column来说就是水平方向的布局方式
- start ,垂直主轴方向(水平方向)左侧对齐;
- end,垂直主轴方向(水平方向)右侧对齐;
- center,垂直主轴方向(水平方向)居中对齐;
- stretch ,垂直主轴方向(水平方向)拉伸子child;
- baseline,这个要和textBaseline一起使用;
因此,对于当前页面,想让标题左对齐,那么我们就需要用到属性:
crossAxisAlignment: CrossAxisAlignment.start,
意思为水平方向,从左边开始布局!
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: Text(
imageModellList[index].title,
style: TextStyle(fontSize: 15, color: Colors.blue),
),
),
Container(
margin: const EdgeInsets.only(left: 10, right: 10),
child: Image.network(imageModellList[index].url),
)
]);
}
实现效果:
当我们不知道某个组件具体有哪些属性时,我们只需要Crtl+鼠标点击去这个组件就可以看到对应的属性了,比如Image:
另外,如果itemBuilder的布局足够复杂,那么这部分代码将足够多,可读性也就越来越差,有什么办法呢?当然!和java一样,提取为一个方法就可以了:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemBuilder: (context, index) => buildItem(imageModellList[index]),
itemCount: imageModellList.length,
));
}
buildItem(ImageModel imageModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
buildText(imageModel.title),
buildImage(imageModel.url)
]);
}
buildText(title) {
return Container(
padding: const EdgeInsets.all(10),
child: Text(
title,
style: TextStyle(fontSize: 15, color: Colors.blue),
),
);
}
buildImage(url) {
return Container(
margin: const EdgeInsets.only(left: 10, right: 10),
child: Image.network(url),
);
}
好了,关于类的创建和引用、listview的使用、基础布局了解和熟悉后,离我们的目标就越来越近了!