zoukankan      html  css  js  c++  java
  • Flutter 流式布局列表实例+上拉加载

    页面变化的几种方式:

    一、StatefulWidget的setState形式

    先声明两个变量。

    int page = 1;
    List<Map> list = [];

    写了一个方法,获取数据:

    void _getHotGoods(){
        var formData = {'page':page};
        request('post', 'homePageBelowConten',formData: formData).then((val){
          var data = json.decode(val.toString());
          List<Map> newList = (data['data'] as List).cast();
          setState(() {
            list.addAll(newList); //新的列表加到老的列表之上
            page ++;
          });
        });
      }

    然后实现页面布局

    标题:

    //火爆专区标题 变量的形式
      Widget hotTitle = Container(
        margin: EdgeInsets.only(top: 10.0),
        alignment: Alignment.center,
        color: Colors.transparent, //透明背景色
        padding: EdgeInsets.all(5.0),
        child: Text('火爆专区'),
      );

    每个子项:

    //火爆专区子项 方法的形式
      Widget _wrapList(){
        if(list.length != 0){
          List<Widget> listWidget = list.map((val){ //把Map类型的List包装成Widget,再放回List里,并赋值给流式布局
            return InkWell(
              onTap: (){},
              child: Container(
                 ScreenUtil().setWidth(372),
                color: Colors.white,
                padding: EdgeInsets.all(5.0),
                margin: EdgeInsets.only(bottom: 3.0),
                child: Column(
                  children: <Widget>[
                    Image.network(val['image'],ScreenUtil().setWidth(370)),
                    Text(
                      val['name'],
                      maxLines: 1,
                      overflow:TextOverflow.ellipsis,
                      style:TextStyle(color:Colors.blueGrey,fontSize:ScreenUtil().setSp(26)),
                    ),
                    Row(
                      children: <Widget>[
                        Text('¥${val['mallPrice']}'),
                        Text(
                          '¥${val['price']}',
                          style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough),
                        )
                      ],
                    ),
                  ],
                ),
              ),
            );
          }).toList(); //把Map类型的List包装成Widget,再放回List里,并赋值给流式布局
    
          return Wrap( //返回流式布局
            spacing: 2, //每行2列
            children: listWidget,
          );
        }else{
          return Text(''); //没有数据时返回空
        }
      }

    组合在一起:

    //火爆专区组合
      Widget _hotGoods(){
        return Container(
          child: Column(
            children: <Widget>[
              hotTitle,
              _wrapList(),
            ],
          ),
        );
      }

    完整代码:

    import 'package:flutter/material.dart';
    import '../service/service_method.dart';
    import 'dart:convert';
    import 'package:flutter_screenutil/flutter_screenutil.dart';
    
    class CategoryPage extends StatefulWidget {
    
      _CategoryPageState createState() => _CategoryPageState();
    }
    
    class _CategoryPageState extends State<CategoryPage> {
      int page = 1;
      List<Map> list = [];
    
      @override
      void initState() { 
        super.initState();
        _getHotGoods(); //火爆专区获取值
      }
    
      @override
      Widget build(BuildContext context) {
        return SingleChildScrollView(
          child:Column(
            children: <Widget>[
               _hotGoods(),
             ],
          ),      
        );
      }
    
      //火爆商品接口
      void _getHotGoods(){
        var formData = {'page':page}; //Map类型
        request('post', 'homePageBelowConten',formData: formData).then((val){
          var data = json.decode(val.toString());
          List<Map> newList = (data['data'] as List).cast();
          setState(() {
            list.addAll(newList); //新的列表加到老的列表之上
            page ++;
          });
        });
      }
      //火爆专区标题 变量的形式
      Widget hotTitle = Container(
        margin: EdgeInsets.only(top: 10.0),
        alignment: Alignment.center,
        color: Colors.transparent, //透明背景色
        padding: EdgeInsets.all(5.0),
        child: Text('火爆专区'),
      );
      //火爆专区子项 方法的形式
      Widget _wrapList(){
        if(list.length != 0){
          List<Widget> listWidget = list.map((val){ //Map循环的形式:把Map类型的List包装成Widget,再放回List里,并赋值给流式布局
            return InkWell(
              onTap: (){},
              child: Container(
                 ScreenUtil().setWidth(372),
                color: Colors.white,
                padding: EdgeInsets.all(5.0),
                margin: EdgeInsets.only(bottom: 3.0),
                child: Column(
                  children: <Widget>[
                    Image.network(val['image'],ScreenUtil().setWidth(370)),
                    Text(
                      val['name'],
                      maxLines: 1,
                      overflow:TextOverflow.ellipsis,
                      style:TextStyle(color:Colors.blueGrey,fontSize:ScreenUtil().setSp(26)),
                    ),
                    Row(
                      children: <Widget>[
                        Text('¥${val['mallPrice']}'),
                        Text(
                          '¥${val['price']}',
                          style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough),
                        )
                      ],
                    ),
                  ],
                ),
              ),
            );
          }).toList(); //Map循环的形式:把Map类型的List包装成Widget,再放回List里,并赋值给流式布局
    
          return Wrap( //返回流式布局
            spacing: 2, //每行2列
            children: listWidget,
          );
        }else{
          return Text(''); //没有数据时返回空
        }
      }
      //火爆专区组合
      Widget _hotGoods(){
        return Container(
          child: Column(
            children: <Widget>[
              hotTitle,
              _wrapList(),
            ],
          ),
        );
      }
    
    }

    flutter_easyrefresh插件:

    EasyRefresh很容易就能在Flutter应用上实现下拉刷新以及上拉加载操作,它支持几乎所有的Flutter控件,但前提是需要包裹成ScrollView。它的功能与Android的SmartRefreshLayout很相似,同样也吸取了很多三方库的优点。EasyRefresh中集成了多种风格的Header和Footer,但是它并没有局限性,你可以很轻松的自定义。使用Flutter强大的动画,甚至随便一个简单的控件也可以完成。EasyRefresh的目标是为Flutter打造一个强大,稳定,成熟的下拉刷新框架。

    github:https://github.com/xuelongqy/flutter_easyrefresh

    flutter_easyrefresh优点:

    • 能够自定义酷炫的Header和Footer,也就是上拉和下拉的效果。
    • 更新及时,不断在完善,录课截至时已经是v1.2.7版本了。
    • 有一个辅导群,虽然文档不太完善,但是有辅导群和详细的案例。
    • 回掉方法简单,这个具体可以看下面的例子。

    引入依赖

    直接在pubspec.yaml中的dependencies中进行引入,主要要用最新版本,文章中的版本不一定是最新版本。

    flutter_easyrefresh: ^1.2.7

    引入后,在要使用的页面用import引入package,代码如下:

    import 'package:flutter_easyrefresh/easy_refresh.dart';

    制作上拉加载效果

    使用这个插件,要求我们必须是一个ListView,所以我们要改造以前的代码,SingleChildScrollView改造成ListView。并添加loadMore,把_getHotGoods的内容粘贴过来,

    _getHotGoods();就可以注掉了。
    return EasyRefresh(
          child:ListView(
            children: <Widget>[
               _hotGoods(),
             ],
          ),
          loadMore: () async{
            var formData = {'page':page}; //Map类型
            await request('post', 'homePageBelowConten',formData: formData).then((val){
              var data = json.decode(val.toString());
              List<Map> newList = (data['data'] as List).cast();
              setState(() {
                list.addAll(newList); //新的列表加到老的列表之上
                page ++;
              });
            });
          },     
        );

    现在运行已经可以看到效果了,不过还需要修改下。

    自定义上拉加载效果

    因为它自带的样式是蓝色的,与我们的界面不太相符,所以我们改造一下,它的底部上拉刷新效果。如果你有兴趣做出更炫酷的效果,可以自行查看一下Github,学习一下。

        refreshFooter:ClassicsFooter( //自定义上拉加载效果
               key:_footerKey,
               bgColor:Colors.white,
               textColor: Colors.blueGrey,
               moreInfoColor: Colors.blueGrey,
               showMore: true,
               noMoreText: '',
               moreInfo: '加载中', //加载时显示的文字
               loadReadyText: '上拉加载...', //准备时显示的文字
             ),

    还要在上面定义Key:

    GlobalKey<RefreshFooterState> _footerKey = new GlobalKey<RefreshFooterState>(); //定义key

    完整代码:

    import 'package:flutter/material.dart';
    import '../service/service_method.dart';
    import 'dart:convert';
    import 'package:flutter_screenutil/flutter_screenutil.dart';
    import 'package:flutter_easyrefresh/easy_refresh.dart';
    
    class CategoryPage extends StatefulWidget {
    
      _CategoryPageState createState() => _CategoryPageState();
    }
    
    class _CategoryPageState extends State<CategoryPage> {
      int page = 1;
      List<Map> list = [];
    
      GlobalKey<RefreshFooterState> _footerKey = new GlobalKey<RefreshFooterState>(); //定义key
    
      @override
      void initState() { 
        super.initState();
        //_getHotGoods(); //火爆专区获取值
      }
    
      @override
      Widget build(BuildContext context) {
        return EasyRefresh(
          refreshFooter:ClassicsFooter( //自定义上拉加载效果
               key:_footerKey,
               bgColor:Colors.white,
               textColor: Colors.blueGrey,
               moreInfoColor: Colors.blueGrey,
               showMore: true,
               noMoreText: '',
               moreInfo: '加载中', //加载时显示的文字
               loadReadyText: '上拉加载...', //准备时显示的文字
          ),
          child:ListView(
            children: <Widget>[
               _hotGoods(),
             ],
          ),
          loadMore: () async{
            var formData = {'page':page}; //Map类型
            await request('post', 'homePageBelowConten',formData: formData).then((val){
              var data = json.decode(val.toString());
              List<Map> newList = (data['data'] as List).cast();
              setState(() {
                list.addAll(newList); //新的列表加到老的列表之上
                page ++;
              });
            });
          },     
        );
      }
    
      //火爆商品接口
      // void _getHotGoods(){
      //   var formData = {'page':page}; //Map类型
      //   request('post', 'homePageBelowConten',formData: formData).then((val){
      //     var data = json.decode(val.toString());
      //     List<Map> newList = (data['data'] as List).cast();
      //     setState(() {
      //       list.addAll(newList); //新的列表加到老的列表之上
      //       page ++;
      //     });
      //   });
      // }
      //火爆专区标题 变量的形式
      Widget hotTitle = Container(
        margin: EdgeInsets.only(top: 10.0),
        alignment: Alignment.center,
        color: Colors.transparent, //透明背景色
        padding: EdgeInsets.all(5.0),
        child: Text('火爆专区'),
      );
      //火爆专区子项 方法的形式
      Widget _wrapList(){
        if(list.length != 0){
          List<Widget> listWidget = list.map((val){ //Map循环的形式:把Map类型的List包装成Widget类型,再放回List里,并赋值给流式布局
            return InkWell(
              onTap: (){},
              child: Container(
                 ScreenUtil().setWidth(372),
                color: Colors.white,
                padding: EdgeInsets.all(5.0),
                margin: EdgeInsets.only(bottom: 3.0),
                child: Column(
                  children: <Widget>[
                    Image.network(val['image'],ScreenUtil().setWidth(370)),
                    Text(
                      val['name'],
                      maxLines: 1,
                      overflow:TextOverflow.ellipsis,
                      style:TextStyle(color:Colors.blueGrey,fontSize:ScreenUtil().setSp(26)),
                    ),
                    Row(
                      children: <Widget>[
                        Text('¥${val['mallPrice']}'),
                        Text(
                          '¥${val['price']}',
                          style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough),
                        )
                      ],
                    ),
                  ],
                ),
              ),
            );
          }).toList(); //Map循环的形式:把Map类型的List包装成Widget类型,再放回List里,并赋值给流式布局
    
          return Wrap( //返回流式布局
            spacing: 2, //每行2列
            children: listWidget,
          );
        }else{
          return Text(''); //没有数据时返回空
        }
      }
      //火爆专区组合
      Widget _hotGoods(){
        return Container(
          child: Column(
            children: <Widget>[
              hotTitle,
              _wrapList(),
            ],
          ),
        );
      }
    
    }
  • 相关阅读:
    在手机浏览器中判断App是否已安装
    用git无法连接github的解决方法
    使用pdf.js显示pdf文件
    Javascript绝句欣赏
    HTTP Keep-Alive模式
    和浏览器并发请求数有关的一些前端技术
    Javascript标准参考教程学习记录
    [nodejs]国内npm安装nodejs modules失败的几个解决方案
    利用sfntly的sfnttool.jar提取中文字体
    Bzoj4378--Poi2015Logistyka
  • 原文地址:https://www.cnblogs.com/joe235/p/11557772.html
Copyright © 2011-2022 走看看