开源库、活动 UI & 功能 编写
Nealyang opened this issue · 0 comments
Nealyang commented
前言
由于前面UI功能基本以及涵盖我们这一章节中所涵盖的知识点。所以活动和开源库的页面,我们将放到一小节中,将关键代码再熟悉一番。不再重复编写同样章节内容。完成该章节我们将完成如下功能开发:
代码地址为:代码地址
定义数据model
- lib/model/activity_cell.dart
import '../util/util.dart';
class ActivityCell{
String pic;
String detailUrl;
String title;
String city;
String time;
ActivityCell({
this.city,
this.detailUrl,
this.pic,
this.time,
this.title
});
factory ActivityCell.formJson(Map<String,dynamic> json){
return ActivityCell(
city: json['city'],
detailUrl: json['eventUrl'],
title:json['title'],
pic:json['screenshot'],
time: Util.getTimeDate(json['startTime'])
);
}
}
- 数据model的定义使我们每一个页面针对该页面的cell总结出来的所需字段,对于从接口获取的字段需要进行处理的数据也同样在这一层中处理,保证改model的数据都是cell可以拿来即用的。比如此处我们使用
Util.getTimeDate
的方法
具体方法如下:
static String getTimeDate(String comTime) {
var compareTime = DateTime.parse(comTime);
String weekDay = '';
switch (compareTime.weekday) {
case 2:
weekDay = '周二';
break;
case 3:
weekDay = '周三';
break;
case 4:
weekDay = '周四';
break;
case 5:
weekDay = '周五';
break;
case 6:
weekDay = '周六';
break;
case 7:
weekDay = '周日';
break;
default:
weekDay = '周一';
}
return '${compareTime.month}-${compareTime.day} $weekDay';
}
请求数据
首先定义基础请求api
// 开源库
static const String REPOS_LIST = 'https://repo-ms.juejin.im/v1/getCustomRepos';
// 活动
static const String ACTIVITY_CITY = 'https://event-storage-api-ms.juejin.im/v1/getCityList';
static const String ACTIVITY_LIST = 'https://event-storage-api-ms.juejin.im/v2/getEventList';
再在lib/util/data_utils.dart
中封装请求方法,这里也是举其一个例子
// 活动列表
static Future<List<ActivityCell>> getActivityList(Map<String,dynamic> params) async{
List<ActivityCell> resultList = [];
var response = await NetUtils.get(Api.ACTIVITY_LIST,params: params);
var responseList = response['d'];
for (int i = 0; i < responseList.length; i++) {
ActivityCell activityCell;
try {
activityCell = ActivityCell.formJson(responseList[i]);
} catch (e) {
print("error $e at $i");
continue;
}
resultList.add(activityCell);
}
return resultList;
}
- 由于我不确定字段是否齐全,毕竟这是掘金开放的api,笔者也没有跟开发约束字段,所以在处理的字段的时候添加了个异常捕获。及时出现了异常,也不会影响代码,并且还能定位哪一个数据有问题。
页面代码编写
这是我们改项目中编写的最后一个完整的页面,所以这里我展示下全部的代码,再最后说明下其中的一些注意事项
- lib/page/repos_page.dart
import 'package:flutter/material.dart';
import '../util/data_utils.dart';
import '../model/repos_cell.dart';
import '../constants/constants.dart';
import '../widgets/repos_list_cell.dart';
import '../widgets/load_more.dart';
import 'dart:core';
import '../widgets/repos_cell_header.dart';
class ReposPage extends StatefulWidget {
_ReposPageState createState() => _ReposPageState();
}
class _ReposPageState extends State<ReposPage> {
List<ReposCell> _listData = <ReposCell>[];
int _indexPage = 0;
Map<String, dynamic> _params = {"src": 'web', "limit": 20};
bool _hasMore = true;
ScrollController _scrollController = ScrollController();
bool _isRequesting = false;
@override
void initState() {
super.initState();
_getListData(false);
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_getListData(true);
}
});
}
_getListData(bool isLoadMore) {
if (_isRequesting || !_hasMore) return;
if (isLoadMore) {
_params['before'] = Constants.REPOS_BEFOR[_indexPage];
}else{
_indexPage = -1;
}
_isRequesting = true;
DataUtils.getReposListData(_params).then((resultData) {
if (this.mounted) {
_indexPage+=1;
List<ReposCell> resultList = [];
if (isLoadMore) {
resultList.addAll(_listData);
}
resultList.addAll(resultData);
setState(() {
_listData = resultList;
_hasMore = _indexPage < Constants.REPOS_BEFOR.length;
_isRequesting = false;
});
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
Widget _itemBuilder(context,index){
if(index == _listData.length+1){
return LoadMore(_hasMore);
}
if(index == 0){
return ReposCellHeader();
}
return ReposListCell(cellData: _listData[index-1]);
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: _itemBuilder,
itemCount: _listData.length+2,
controller: _scrollController,
);
}
}
- 顶部import相关组件,设计该页面的是
repos_cell_header
,repos_list_cell
,data_util
为页面请求数据封装的方法。load_more
是底部加载更多的组件,需要传递hasMore
来确认UI长什么样子。dart:core
为dart中的核心库,包含Uri的加密解密等 - 页面继承
StatefulWidget
类,因为会涉及到页面UI的改变,请求数据我们需要在内部定义盛放数据的list,pageIndex、请求参数、是否还有下一页、是否正在请求(防止触底后不断发送页面请求) - 长列表使用
ListViedw.builder
方法来构建,毕竟性能好,构建需要初始化 ScrollController ,ScrollController可以给列表设置长度,并且还可以检测页面滚动,检测触底,在页面初始化的时候添加这些监听。 - 在请求数据的时候,需要根据页面当前的状态(isRequesting、hasMore、isLoadMore)来决定进行什么操作
- 最后由于我们初始化 ScrollController ,所以需要在页面
dispose
的时候及时释放相应资源,以保证手机性能
完整代码地址:代码地址