Json
1. Json 使用
- 01: 现将json文件拖入到新建assets文件夹下
- 02: 在pubspec.yaml 文件下配置路径
# To add assets to your application, add an assets section, like this:
assets:
- assets/flutter.json
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
2. Json 读取
- 01: 导入头文件Buddle: import ‘package:flutter/services.dart‘ show rootBundle;
- 02: 通过Future 异步获取:
- 03: 创建model 模型进行遍历dict转模型
import ‘dart:convert‘;
import ‘package:flutter/services.dart‘ show rootBundle;
import ‘package:flutter_listview_json/homeModel.dart‘;
Future<List<HomeModel>> getHomeViweModel() async {
// 读取json文件
String jsonString = await rootBundle.loadString(‘assets/flutter.json‘);
// 转成list或者map
final result = json.decode(jsonString);
// 遍历转成模型
List<HomeModel> models = [];
for (Map<String, dynamic> map in result) {
models.add(HomeModel.withMap(map));
}
// 返回模型数据
return models;
}
class HomeModel {
String title;
String description;
String img;
HomeModel(this.title, this.description, this.img);
HomeModel.withMap(Map<String, dynamic> map) {
this.title = map[‘title‘];
this.description = map[‘description‘];
this.img = map[‘img‘];
}
}
ListView
1. ListView 基本使用
- ListView可以沿一个方向(垂直或水平方向,默认是垂直方向)来排列其所有子Widget。
// ListView 的基本直接使用
class Content extends StatelessWidget {
final TextStyle textStyle = TextStyle(fontSize: 20, color: Colors.redAccent);
@override
Widget build(BuildContext context) {
return ListView(
children: [
Padding(
padding: EdgeInsets.all(8),
child: Text("雪野茫茫,你知道一颗小草的梦吗?", style: textStyle),
),
Padding(
padding: EdgeInsets.all(8),
child: Text("窗前托腮沉思的少女,你是想做一朵云的诗,还是做一只蝶的画?", style: textStyle),
),
Padding(
padding: EdgeInsets.all(8),
child: Text("没有泪水的人,她的眼睛是干涸的;没有梦的人,他的夜是黑暗的。", style: textStyle),
),
],
);
}
}
2. ListTile
- 在开发中,我们经常见到一种列表,有一个图标或图片(Icon), 有一个标题(Title),有一个子标题(Subtitle),还有尾部一个图标(Icon)
class Content2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: [
ListTile(
leading: Icon(
Icons.people,
size: 20,
color: Colors.red,
),
title: Text(‘联系人:ListTile‘),
subtitle: Text(‘联系人信息‘),
trailing: Icon(Icons.arrow_forward_ios),
tileColor: Colors.greenAccent,
),
ListTile(
leading: Icon(
Icons.email,
size: 20,
),
title: Text(‘邮箱:ListTile‘),
subtitle: Text(‘邮箱地址信息‘),
trailing: Icon(Icons.arrow_forward_ios),
),
ListTile(
leading: Icon(
Icons.message,
size: 20,
),
title: Text(‘消息:ListTile‘),
subtitle: Text(‘消息详情信息‘),
trailing: Icon(Icons.arrow_forward_ios),
tileColor: Colors.yellow,
),
ListTile(
leading: Icon(
Icons.map,
size: 20,
),
title: Text(‘地址:ListTile‘),
subtitle: Text(‘地址详情信息‘),
trailing: Icon(Icons.arrow_forward_ios),
tileColor: Colors.blue,
),
],
);
}
}
3. ListView 水平方向使用
- ListView 滚动方向: 水平和垂直
- 水平: 需要设置Container宽度或者设置每一个item的宽度itemExtent
- 垂直: 不需要设置其他
/* ListView 滚动方向: 水平和垂直
水平: 需要设置Container宽度或者设置每一个item的宽度itemExtent
垂直: 不需要设置其他
*/
class Content3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,
itemExtent: 375, // 设置所有item的统一宽度
children: [
Container(color: Colors.red, width: 100), // 设置每一个独立的宽度
Container(color: Colors.greenAccent, width: 200),
Container(color: Colors.blue, width: 300),
Container(color: Colors.purple, width: 300),
Container(color: Colors.orange, width: 300),
],
);
}
}
4. ListView.build 基本使用
- 通过构造函数children传入所有子widget会一次性创建所有的widget、性能很差、而且会增加首屏的渲染时间. 我们可以使用ListView.build来构建Widget,提高性能.
- ListView.build:
- 适用于数据比较多的时候
- 当列表滚动到对应位置的时候、ListView就会自动调用该方法来创建对应的子Widget,类型是IndexedWidgetBuilder, 是一个函数类型.
- itemCount: 表示列表项的数量,如果为空,则表示ListView为无限列表.
class Content4 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 100,
itemExtent: 200,
itemBuilder: (BuildContext context, int index) {
print(‘###: index:$index‘);
return ListTile(
title: Text(‘标题$index‘),
subtitle: Text(‘详情内容$index‘),
tileColor: (index % 2 == 0) ? Colors.orange : Colors.purple,
);
},
);
}
}
5. ListView.build 动态数据展示
- 由于json数据获取是异步加载的、无法使用statelessWidget来渲染
- 刚开始界面并不会显示数据、后面json加载出来数据后、再次展示加载的数据。
class Content5 extends StatefulWidget {
@override
_Content5State createState() => _Content5State();
}
class _Content5State extends State<Content5> {
List<HomeModel> models = [];
@override
void initState() {
getHomeViweModel().then((value) {
setState(() {
this.models = value;
});
});
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: this.models.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(0),
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Image.network(
this.models[index].img,
fit: BoxFit.fitWidth,
width: MediaQuery.of(context).size.width,
),
SizedBox(height: 10),
Text(
‘电影名: ${this.models[index].title}‘,
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
Text(
‘电影简介: ${this.models[index].description}‘,
style: TextStyle(fontSize: 10),
),
SizedBox(height: 10),
Container(
color: Colors.grey,
width: MediaQuery.of(context).size.width,
height: 0,
),
]),
);
});
}
}
6. ListView.separated 使用
- ListView.separated 比ListView.build 多了一个参数 separatorBuild参数, 该参数是一个分割器生成器
- Divider: 分割器生成器Widget
class Content6 extends StatelessWidget {
Divider blueColor = Divider(color: Colors.blue);
Divider redColor = Divider(color: Colors.red);
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Icon(Icons.people),
title: Text(‘联系人: ${index + 1}‘),
subtitle: Text(‘联系人电话: ${index + 1}‘),
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(
color: Colors.grey,
height: 0,
thickness: 0.25, // 厚度
);
return index % 2 == 0 ? blueColor : redColor;
},
itemCount: 20,
);
}
}
[Flutter-21] ListView & Json