美文网首页Flutter圈子Flutter中文社区Flutter
flutter实战3:解析HTTP请求数据和制作新闻分类列表

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

作者: 燃烧的鱼丸 | 来源:发表于2018-04-03 01:12 被阅读583次

    当我们搭建好了整个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)共同成长,谢谢大家~

    相关文章

      网友评论

      • longzekai:这么看来Flutter 现在确实还很不完善啊。

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

      本文链接:https://www.haomeiwen.com/subject/blyncftx.html