Flutter_Weather今日热点模块实现

作者: 深情不及酒伴 | 来源:发表于2019-07-31 21:18 被阅读2次

    Flutter_Weather今日热点模块实现,效果图如下:


    image

    首页布局实现

    布局

    代码如下:

      @override
      Widget build(BuildContext context) {
        return _buildTabController();
      }
    
      Widget _buildTabController(){
        if(tabs.length == 0){
          return ProgressView();
        }else {
          return DefaultTabController(
              length: tabs.length,
              child: Scaffold(
                appBar: AppBar(
                  title: buildSearch(context),
                  bottom: TabBar(
                    isScrollable: true,
                    tabs: tabs.map<Widget>((dynamic title) {
                      return Tab(
                        text: title.toString(),
                      );
                    }).toList(),
                  ),
                ),
                body: TabBarView(
                    children: tabs.map<Widget>((dynamic title) {
                      return Container(
                          child: new NewListPage(type: title.toString(),));
                    }).toList()),
              ));
        }
      }
    

    因为TabBar的标题是网络加载,所以要有个一加载ProgressView,加载成功后显示布局。
    使用DefaultTabController控制tabBar和tabBarView联动

    搜索框实现
    在这里插入图片描述

    横向排列的3个widget,所以使用Row进行包裹。使用Container的BoxDecoration设置圆角属性。使用Expanded填充中间的空白区域,使热搜显示在最右边。

    最后别忘了添加点击事件,跳转到搜索页面。代码如下

      //搜索框
      Widget buildSearch(BuildContext context) {
        return  GestureDetector(
          onTap: (){
            //通过路由进行页面跳转
              Application.router.navigateTo(context, Routes.searchPage);
          },
          child: Container(
          //添加圆角属性
            decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.all(Radius.circular(10))),
            padding: EdgeInsets.all(8),
            height: 40,
            child: Row(
            //设置子widget居中对齐
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Icon(
                  Icons.search,
                  color: Colors.grey,
                  size: 20,
                ),
                SizedBox(
                  width: 5,
                ),
                //填充空间
                Expanded(
                    child: Text("搜你想要的",
                        overflow: TextOverflow.ellipsis,
                        style: TextStyle(fontSize: 14, color: Colors.black54))),
                Text(
                  "热搜",
                  style: TextStyle(color: Colors.blue, fontSize: 15),
                )
              ],
            ),
          ),
        );
      }
    
    加载数据并解析

    使用http加载数据

      //加载tabbar数据
      loadData() async {
    //    final response =
    //        await http.post(Api.NEWS_TITLE_JS, body: {'appkey': Api.APPKEY_JS});
    //由于接口有次数限制,所以直接把数据拿过来,节约接口次数
      String data = '{"status":0,"msg":"ok","result":["头条","新闻","国内","国际","政治","财经","体育","娱乐","军事","教育","科技","NBA","股票","星座","女性","健康","育儿"]}';
        Map map = json.decode(data);
        //result返回一个String数组,可以直接解析
        var list = map['result'];
        setState(() {
          tabs.addAll(list);
        });
      }
    

    加载完成以后,调用setState()刷新widget。

    下面我们来看一下TabBarView中的NewListPage的实现

    消息列表的实现

    布局

    布局很简单,就是一个ListView,因为有刷新的存在,所以我们要在ListView的外面套上RefreshIndicator,实现刷新。代如下:

      @override
      Widget build(BuildContext context) {
      
        return new RefreshIndicator(
            child: buildListView(),
            onRefresh: _handlerRefresh,
        );
      }
    
    • onRefresh:触发刷新的回调
    • child : 返回一个listview
    listview实现
      List<NewsItem> list = [null];
    
      //listview
      Widget buildListView(){
        return new ListView.builder(
            itemCount: list.length,
            itemBuilder: (context, position) {
              if(list[position] == null){
                //显示加载更多
                return Container(
                  alignment: Alignment.center,
                  height: 40,child:SizedBox(height : 30,width :30 ,
                  child: CircularProgressIndicator(strokeWidth: 2,),));
              }else{
                return getRow(position);
              }
            },
            controller: _scrollController,
            );
      }
    

    我们在初始化数据源list的时候给list初始化了一个null作为标记位置(不推荐设置为null)List<NewsItem> list = [null];这样就可以在listview中根据list[position] == null来判断是不是到了标记位,如果到了就显示加载的widget。当然也可以在这个地方做加载更多的数据请求。

    加载更多

    我把加载更多放到_scrollController中去了

      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        _scrollController.addListener((){
          //滑到最底部
          if(_scrollController.position.pixels == _scrollController.position.maxScrollExtent){
            //加载更多
            print("滑动到底部");
            start = list.length - 1;
            loadData();
          }else{
    
          }
        });
        loadData();
      }
    
    下拉刷新回调

    _handlerRefresh为刷新是的回调,代码如下

      //刷新
      Future<Null> _handlerRefresh() async{
        start = 0;
        loadData();
        return null;
      }
    
    
    加载数据
      //加载数据
      loadData() async {
        final response = await http.post(Api.NEWS_LIST_JS+"?channel=$type&appkey=${Api.APPKEY_JS}&start=$start}",);
        //刷新
        setState(() {
          print("response list:" + response.body);
          NewsBean newsBean = NewsBean.fromJson(json.decode(response.body));
          if(newsBean.status == "0"){
            //表示刷新
            if(start == 0 && list.length > 0){
              list.clear();
              list.add(null);
            }
            NewResult result = newsBean.result;
            //把null放到最后一位
            list.insertAll(list.length-1,result.list);
          }
        });
      }
    
    listview的item布局
    在这里插入图片描述
    • 红色是最外层是一个column,里面包裹内容和下划线。
    • 黄色是内容里面用一个row包裹
    • 蓝色是文字,是一个column。

    最后在使用GestureDetector包裹整个布局,给item添加点击事件。

    代码如下:

      Widget getRow(int index) {
        NewsItem item = list[index];
        return GestureDetector(
            child: Container(
            margin: EdgeInsets.only(left: 10, top: 10, right: 10),
            child: Column(
              children: <Widget>[
                Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    //文字
                    new Expanded(
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text(
                              item.title,
                              style: TextStyle(
                                  fontSize: 18,
                                  color: Colors.black
                              ),
                              overflow: TextOverflow.ellipsis,
                              maxLines: 2,
                            ),
                            SizedBox(height: 5,),
                            Text(item.src + "  " + TimeUtil.getNewsTime(item.time),
                              style: TextStyle(color: Colors.grey,fontSize: 12),),
                          ],
                        )),
                    //图片
                    Image.network(
                      item.pic,
                      height: 65,
                      width: 95,
                      fit: BoxFit.cover,
                    ),
                  ],
                ),
                //分割线
                Padding(
                  padding: EdgeInsets.only(top: 10),
                  child: SizedBox(height: 1, child: Container(color: Color(0xffE8E8E8),)),
                )
              ],
            ),
          ),
          onTap: (){
            Application.router.navigateTo(context,
                '${Routes.webViewPage}?title=${Uri.encodeComponent(item.title)}&url=${Uri.encodeComponent(item.url)}');
          },
        );
      }
    

    WebView实现

    class WebViewPage extends StatefulWidget{
    
      final String url;
      final String title;
    
      WebViewPage(this.url,this.title);
    
      @override
      State<StatefulWidget> createState() {
        // TODO: implement createState
        return _PageState();
      }
    }
    
    class _PageState extends State<WebViewPage>{
      @override
      Widget build(BuildContext context) {
        print("WebViewPage  url:" + widget.url + "  title:" + widget.title);
        // TODO: implement build
        return new WebviewScaffold(
            appBar: new AppBar(
              backgroundColor: Color(0xff333333),
              title: Text(widget.title),
            ),
            url: widget.url,
            withZoom: false,
            withLocalStorage: true,
            withJavascript: true,
            initialChild: Center(child: Text("初始化"),),
          );
      }
    
    }
    

    android使用WebView的时候要在Android/../manifest 配置文件中的application中添加
    android:usesCleartextTraffic="true",不然报http异常。

    项目完整地址:https://github.com/Zhengyi66/Flutter_weather

    相关文章

      网友评论

        本文标题:Flutter_Weather今日热点模块实现

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