「这是我参加11月更文挑战的第12天,活动详情查看:2021最终一次更文挑战」
Hi
- Wechat: RyukieW
- 微信公众号:LabLawliet
- 技术文章归档
- Github
我的个人项目 | 扫雷Elic 无尽天梯 | 梦见账本 | 隐私拜访记载 |
---|---|---|---|
类型 | 游戏 | 财务 | 东西 |
AppStore | Elic | Umemi | 隐私拜访记载 |
更多专栏:
Lawliet的独立开发碎碎念
Lawliet的iOS游园会
Lawliet的iOS底层实验室
Lawliet的iOS逆向实验室
Lawliet的刷题小本本
Lawliet的Flutter实验室
Flutter小技巧|从侧索引条封装看手势处理与clamp函数
Flutter小技巧|Widget初始化办法重写&链式调用&排序
Flutter小技巧|经过多样式Cell看断语
Flutter小技巧|ListView滑动到分组头部
前语
在 iOS 开发中 咱们经常运用 CocoaPods 等东西进行包办理。那么在 flutter 开发中又该怎么进行呢?
这儿以会话列表为例结合导入网络库:http进行解读。
一、 导入依靠库
这是官方供给来一个网络库:http
点击仿制
1.1 修正 pubspec.yaml 配置文件
将仿制的信息补充进配置文件
1.2 更新依靠库
1.3 在运用的当地导入
import 'package:http/http.dart' as http;
二、 异步函数
2.1 简略汇总Service
简略汇总一下Service,便于后续运用。
import 'package:flutter/material.dart';
class ServiceURL {
/// 会话列表
static Uri conversationList = Uri.parse('xxxxxx');
}
2.2 发送恳求
这儿简略选择在 initState 中进行网络恳求,调用移步办法
@override
void initState() {
super.initState();
_loadConversation();
}
/// 加载会话列表
void _loadConversation() async {
var response = await http.get(ServiceURL.conversationList);
print(response.body);
}
这儿可以发现,和咱们在 iOS
开发中的网络恳求的调用形式有很大不同。iOS
开发中咱们都是经过回调的形式接纳恳求结果的。这儿运用 await
。
三、 数据模型转换
接纳到网络数据后咱们天然需求进行数据模型的转换。
3.1 界说数据模型
import 'package:flutter/material.dart';
class ConversationData {
final String nick;
final String avatar;
final String lastestMessage;
ConversationData({
required this.nick,
required this.avatar,
required this.lastestMessage,
});
factory ConversationData.formMap(Map map) {
return ConversationData(
nick: map['nick'],
avatar: map['avatar'],
lastestMessage: map['lastest_message'],
);
}
}
3.2 Json 转 Map
List _conversations = [];
/// 加载会话列表
void _loadConversation() async {
var response = await http.get(ServiceURL.conversationList);
if (response.statusCode == 200) {
final bodyMap = json.decode(response.body);
_conversations = bodyMap['lists']
.map((item) {
return ConversationData.formMap(item);
})
.toList();
} else {
throw Exception('恳求失利:${response.statusCode}');
}
}
3.3 构建 Cell
- Text
- 样式设置
- 缩略方法设置
- 设置最大宽度
- Container
- 设置图片圆角
class ConversationCell extends StatelessWidget {
ConversationCell({required this.conversation});
final ConversationData conversation;
@override
Widget build(BuildContext context) {
return Container(
height: 60,
color: Colors.white,
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(
width: 12,
),
// 圆角
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
image: DecorationImage(
// 网络图片
image: NetworkImage(conversation.avatar),
),
),
),
const SizedBox(
width: 12,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 12),
Text(
conversation.nick,
maxLines: 1,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
Container(
// 限制宽度
width: UIConfig.screenWidth(context) * 0.7,
child: Text(
conversation.lastestMessage,
maxLines: 1,
// 缩略样式
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
)
],
),
],
),
),
),
// 分割线
Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: const EdgeInsets.only(left: 70),
height: 0.5,
color: Colors.grey,
),
),
],
),
);
}
}
3.4 构建 ListView
Widget _itemForRow(BuildContext context, int index) {
return ConversationCell(conversation: _conversations[index]);
}
body: Container(
color: Colors.yellow,
child: ListView.builder(
itemBuilder: _itemForRow,
itemCount: _conversations.length,
),
),
3.5 效果
四、 Future & FutureBuilder
4.1 恳求办法修正
之前的加载办法:
/// 加载会话列表
void _loadConversation() async {
var response = await http.get(ServiceURL.conversationList);
if (response.statusCode == 200) {
final bodyMap = json.decode(response.body);
_conversations = bodyMap['lists']
.map((item) {
return ConversationData.formMap(item);
})
.toList();
} else {
throw Exception('恳求失利:${response.statusCode}');
}
}
修正为:
/// 加载会话列表
Future<List> _loadConversation() async {
var response = await http.get(ServiceURL.conversationList);
if (response.statusCode == 200) {
final bodyMap = json.decode(response.body);
return bodyMap['lists'].map((item) {
return ConversationData.formMap(item);
}).toList();
} else {
throw Exception('恳求失利:${response.statusCode}');
}
}
4.2 ListView 修正
AsyncSnapshot
包含有绑定的 future 回调的数据,也包含异步任务的状况。咱们可以用来判别是否展示加载页面。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(...),
body: Container(
color: Colors.yellow,
child: FutureBuilder(
// 传入 Future
future: _loadConversation(),
builder: (context, AsyncSnapshot snap){
// 判别恳求状况
if (snap.connectionState != ConnectionState.done) {
return const Center(
child: Text('Loading'),
);
}
// 根据结果处理数据展示
return ListView(
children: snap.data.map<Widget>((item){
return ConversationCell(conversation: item);
}).toList(),
);
},
),
),
);
}
4.3 看看效果
五、 结合上面两种方法
结合上面两种方法,这儿运用 Future 调整加载数据的函数。
5.1 恳求函数修正
/// 加载会话列表
Future<List> _loadConversation() async {
_isLoading = true;
var response = await http.get(ServiceURL.conversationList);
_isLoading = false;
if (response.statusCode == 200) {
final bodyMap = json.decode(response.body);
final result = bodyMap['lists'].map((item) {
return ConversationData.formMap(item);
}).toList();
return result;
} else {
throw Exception('恳求失利:${response.statusCode}');
}
}
5.2 回调处理
@override
void initState() {
super.initState();
_loadConversation().then((value) {
// value 就是 Future 里 return 的结果
setState(() {
_conversations = value;
});
});
}
5.3 反常处理
经过 Future 咱们也可以捕捉反常。
@override
void initState() {
super.initState();
_loadConversation().then((value) {
setState(() {
_conversations = value;
});
}).catchError((error) {
print(error);
});
}
六、 总结
- 第一种方法愈加接近咱们 iOS 开发中的思路
- 第二种方法 Future & FutureBuilder 愈加充分利用 Future 特性
- 而结合二者的方法则对我这个iOS刚入门Flutter的新手而言,愈加了解一起也有一些新的体验