flutter实战3:解析HTTP请求数据和制作新闻分类列表

当我们搭建好了整个APP的页面框架,现在我往Tab页里加点东西:各种分类的新闻列表。也可以参考我的Git,上面有要点注释。

本次的任务目的

由于需要请求外部数据,因此引入一个较为方便的http库。官方示例的httpClient也是可以的,但是坑略多,待会儿讲。

第一步

调整代码结构,定义一个Tab页内通用的列表对象,这种场景下使用ListView.builder()创建不定长度的列表:

//因为列表的长度不定,因此需要用有状态类来承载列表
class NewsList extends StatefulWidget{
  final String newsType;    //新闻类型
  @override
  NewsList({Key key, this.newsType} ):super(key:key);

  _NewsListState createState() => new _NewsListState();
}

class _NewsListState extends State<NewsList>{
  ...
  @override
  Widget build(BuildContext context){
    return new ListView.builder(        //ListView.builder非常适合用于创建不确定长度的的列表
        padding: const EdgeInsets.all(16.0),
        itemCount: data == null ? 0 : data.length,
        itemBuilder: (context, i) {
          return _newsRow(data[i]);//把数据项塞入ListView中
        }
      );
  }
  ...
}

Tab页的数据表达进行结构化处理,在最外层定义新闻Tab页的类,方便后面使用:

//定义TAB页对象,这样做的好处就是,可以灵活定义每个tab页用到的对象,可结合Iterable对象使用,以后讲
class NewsTab {
  String text;
  NewsList newsList;
  NewsTab(this.text,this.newsList);
}

_MyTabbedPageState对象中实例化这些Tab:

//将每个Tab页都结构化处理下,由于http的请求需要传入新闻类型的参数newsType,因此将新闻类型参数值作为对象属性传入Tab中
  final List<NewsTab> myTabs = <NewsTab>[
    new NewsTab('头条',new NewsList(newsType: 'toutiao')),    //拼音就是参数值
    new NewsTab('社会',new NewsList(newsType: 'shehui')),
    new NewsTab('国内',new NewsList(newsType: 'guonei')),
    new NewsTab('国际',new NewsList(newsType: 'guoji')),
    new NewsTab('娱乐',new NewsList(newsType: 'yule')),
    new NewsTab('体育',new NewsList(newsType: 'tiyu')),
    new NewsTab('军事',new NewsList(newsType: 'junshi')),
    new NewsTab('科技',new NewsList(newsType: 'keji')),
    new NewsTab('财经',new NewsList(newsType: 'caijing')),
    new NewsTab('时尚',new NewsList(newsType: 'shishang')),
  ];

第二步

由于重新了Tabs,原来的TabBar和TabBarView获取对应值的方式也发生了改变,用map+toList方法处理下:

@override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        backgroundColor: Colors.orangeAccent,
        title: new TabBar(
          controller: _tabController,
          tabs: myTabs.map((NewsTab item){      //NewsTab可以不用声明
            return new Tab(text: item.text==null?'错误':item.text);
          }).toList(),    //记住要用toList()转换一下map的结果,否则会由于类型不匹配而报错
          indicatorColor: Colors.white,
          isScrollable: true,   //水平滚动的开关,开启后Tab标签可自适应宽度并可横向拉动,并自动从左到右排列,默认关闭
        ),
      ),
      body: new TabBarView(
        controller: _tabController,
        children: myTabs.map((item) {
          return item.newsList; //使用参数值
        }).toList(),
      ),
    );
  }

以上对新闻页面的结构进行了重构,重头戏就是完善NewsList对象。于是乎,在初始化NewsList对象时发起HTTP请求应该是个不错的办法:

initState方法中数据初始化

具体是怎么初始化数据的,第三步会讲到,踩了不少坑。这里的重点是,Flutter提倡数据驱动组件的创建,组件自己无法触发动态创建对象,只有通过数据绑定的方式,实现对象的重绘和动态加载,原理和react类似,比如:

数据驱动组件重绘

第三步

到了这一步,完全进入踩坑模式。

  • 踩坑1 http和httpclient都是IO异步操作,其内置的请求函数的返回值是Future类型对象,需要提前声明定义类型如:Future<String>,返回值也需要await异步处理后才可以转换成需要的数据类型:
Future的数据类型注意事项

上图中列举了两种方法,建议使用下面那种,因为如果能从返回值中提取请求获取的数据,即可将所有的http请求封装到API文件中去,不必写在页面代码中,原因大家都懂的。
注意在setState()之前有一句if(!mounted) return,因为异步请求数据和控件的渲染是同时进行的,如果代码已经执行到了setState,但是数据还没有获取到,此时setState触发的控件渲染就会报错,为了避免这种空值错误,在setState之前先判断空间是否已经渲染完成,mountedFlutter内置的当前控件的状态标识,记住就好。

  • 踩坑2 在ListView直属的Column里面不能用Expanded控件
    Column里面不能用Expanded控件

图中的提示说使用Flexible控件更佳,然而实际上Flexible也会报错。报错的英文大概意思是ListView控件生成未知长度的列表时,总是会自动压缩每一个子元素的高度,而ExpandedFlexible都是可以自由伸缩的控件,造成ListView的子元素无法确定绘制的高度,为了使超出屏幕宽度的新闻标题自动换行,这个时候用ListTile顶替一下吧。

  • 踩坑3 处理不同新闻图片数量不一致的问题
想象中的样子

如上图,肯定是不行的,控件的子元素是不允许为空的,于是使用条件判断的方式封装一下:

根据图片数量的不同插入合适尺寸样式的图片
  • 踩坑3 深刻体会map数组和Object数组的使用,newsinfo.["title"]newsinfo.title两者的newsinfo类型是不一样的,详细还是到源码中去体会吧,注意对比newsinfomyTab这两个的用法。

这次页面写的非常辛苦,而且还没实现滚动刷新或顶部下拉刷新的效果,下一篇再更吧,还有很多要点我在源码中有标识,可以去我的Git中慢慢品味,今天就更到这里,滚去睡觉,真的来不起了。

感谢大家的支持,请关注我的Flutter圈子,多多投稿,也可以加入flutter 中文社区(官方QQ群:338252156)共同成长,谢谢大家~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,793评论 25 707
  • 佛说:人生有八苦:生,老,病,死,爱别离,怨长久,求不得,放不下。时间就像一场回不去的旅行;争不过朝夕,又...
    岁月神偷123阅读 466评论 0 0
  • 端午节作为四大传统节日之一,节日的气氛自当异常浓烈。关于端午,好像有永远讨论不完的话题,今天总结一下关于端午那些事...
    Joyful_Cheung阅读 274评论 4 2
  • 近期看了一些文章讲制定计划的重要性及制定方法,这使我想到了一句谚语“一年之计在于春,一天之计在于晨”。 计划容易,...
    霹雳小青龙阅读 1,700评论 0 1