Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

开源库、活动 UI & 功能 编写 #31

Open
Nealyang opened this issue Mar 19, 2019 · 0 comments
Open

开源库、活动 UI & 功能 编写 #31

Nealyang opened this issue Mar 19, 2019 · 0 comments
Labels

Comments

@Nealyang
Copy link
Owner

前言

由于前面UI功能基本以及涵盖我们这一章节中所涵盖的知识点。所以活动和开源库的页面,我们将放到一小节中,将关键代码再熟悉一番。不再重复编写同样章节内容。完成该章节我们将完成如下功能开发:

img

代码地址为:代码地址

定义数据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的时候及时释放相应资源,以保证手机性能

完整代码地址:代码地址

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant