Flutter listview 上手心得(下拉刷新,上拉加载)

其实作为菜鸟的我是希望flutter能有一个star很高的插件出来,就不用自己整这东西了。

这里记录一下我的实现逻辑,希望不要误导了小菜鸟,,,

刷新用的是父组件 RefreshIndicator ,加载更多是监听的listview

源码在这

在这里插入图片描述)

1.先写两个组件,一个叫做“加载中…”,一个叫做“—我是有底线的—”

代码片段如下:

 Widget _loadMoreWidget() {
    return Container(
      height: 50,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(right: 10),
            height: 20,
            width: 20,
            child: CircularProgressIndicator(
              strokeWidth: 2.0,
              backgroundColor: Colors.grey,
              // value: 0.2,
              valueColor: new AlwaysStoppedAnimation<Color>(Colors.grey),
            ),
          ),
          Container(
            child: Text("正在加载中...",
                style: TextStyle(color: Color(0xff666666), fontSize: 12)),
          )
        ],
      ),
    );
  }
 Widget _endWidget() {
    return Container(
      height: 50,
      child: Text(
        "---  我是有底线的  ---",
        style: TextStyle(color: Color(0xff666666), fontSize: 12),
      ),
    );
  }

2.准备listview ,用的builder方法,因为这个方法没有横线,

onRefresh:是刷新操作
itemBuilder:需传入listView的组件
itemCount:因为position=0时我是banner组件,postion(1,length-2)是数据,最后一行是“加载更多”或者“底线”
controller:是为了监听滑到最底下

         drawer: MyDrawer(),
          body: RefreshIndicator(
            onRefresh: _getListRefreshData,
            child: ListView.builder(
              itemBuilder: _mainWidget,
              itemCount: _articleList.length == 0 ? 1 : _articleList.length + 2,
              controller: _scrollController,
            ),
          )),

3.刷新和加载更多的逻辑,
刷新很简单,传个page=0,就搞定:

 //我是刷新网络数据
  Future<void> _getListRefreshData() async {
    NetService().getArticleList((ArticleModel bean) {
      setState(() {
        _articleList = bean.data.datas;
      });
    }, 0);
  }

我声明了个bool hasMore来记录是不是有更多,没有更多的话就停止监听,并且显示“我是有底线的”

(1)监听

class HomPageState extends State<HomePage> {
  var parentContext;

  List<BannerData> _bannerList = new List();
  List<ArticleDatas> _articleList = new List();

  //分页加载的页数
  int _page = 0;
  bool _hasMore = true;
  ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    //初始加载网络数据
    _getBannerData();
    _getListData(0);
    _scrollController.addListener(() {
      if (_hasMore) {
        //滑动到底
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          _page++;
          _getListData(_page);
        }
      }
    });
  }

(2) 加载没有更多的逻辑

定的20条,所以刷下来数据小于20条我就认为没有更多了,但是数据还是正常加进去

 //我是加载更多
  _getListData(int page) async {
    NetService().getArticleList((ArticleModel bean) {
      if (bean.data.datas.length < 20) {
        _hasMore = false;
      }
      setState(() {
        _articleList.addAll(bean.data.datas);
      });
    }, page);
  }

当没有更多了监听就得停下来了:如(1)

当没有更多了,最下面就显示我是底线啦。。。

 Widget _mainWidget(BuildContext context, int position) {
   //轮播图 --- 列表 --列表的最后一个(“加载更多”,“----底线---”)
    if (position == 0) {
      return Container(
        height: 200,
        child: _bannerList.length == 0 ? Text("") : _swiper(),
      );
    } else if (position == _articleList.length + 1) {
      if (_hasMore) {
        return _loadMoreWidget();
      } else {
        return _endWidget();
      }
    } else {
      return _itemWidget(context, position);
    }
  }

全部代码:

import 'package:flutter/material.dart';
import 'package:wan_flutter/api/net/NetService.dart';
import 'package:wan_flutter/model/ArticleModel.dart';
import 'package:wan_flutter/model/BannerModel.dart';
import 'package:wan_flutter/ui/main/MyDrawer.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:wan_flutter/ui/webview/MyWebViewPage.dart';

class HomePage extends StatefulWidget {
  final mContext;
  const HomePage({Key key, this.mContext}) : super(key: key);

  @override
  State<StatefulWidget> createState() => HomPageState();
}

class HomPageState extends State<HomePage> {
  var parentContext;

  List<BannerData> _bannerList = new List();
  List<ArticleDatas> _articleList = new List();

  //分页加载的页数
  int _page = 0;
  bool _hasMore = true;
  ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    //初始加载网络数据
    _getBannerData();
    _getListData(0);
    _scrollController.addListener(() {
      if (_hasMore) {
        //滑动到底
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          _page++;
          _getListData(_page);
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    parentContext = widget.mContext;
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: Text("首页"),
            elevation: 0.2,
            actions: <Widget>[
              IconButton(
                icon: Icon(
                  Icons.search,
                  color: Colors.white,
                ),
                onPressed: () {},
              )
            ],
          ),
          drawer: MyDrawer(),
          body: RefreshIndicator(
            onRefresh: _getListRefreshData,
            child: ListView.builder(
              itemBuilder: _mainWidget,
              itemCount: _articleList.length == 0 ? 1 : _articleList.length + 2,
              controller: _scrollController,
            ),
          )),
    );
  }

  Widget _mainWidget(BuildContext context, int position) {
    if (position == 0) {
      return Container(
        height: 200,
        child: _bannerList.length == 0 ? Text("") : _swiper(),
      );
    } else if (position == _articleList.length + 1) {
      if (_hasMore) {
        return _loadMoreWidget();
      } else {
        return _endWidget();
      }
    } else {
      return _itemWidget(context, position);
    }
  }

  Swiper _swiper() {
    return Swiper(
      autoplay: true,
      autoplayDelay: 10000,
      scrollDirection: Axis.horizontal,
      pagination: SwiperPagination(
          builder: DotSwiperPaginationBuilder(
              size: 5, //点点没选中时候的大小
              activeSize: 8, //点点选中后的大小
              color: Colors.white, //点点的颜色
              activeColor: Colors.deepOrangeAccent),
          alignment: Alignment.bottomRight),
      itemCount: _bannerList.length,
      itemBuilder: (BuildContext context, int index) {
        return Image.network(
          _bannerList[index].imagePath,
          fit: BoxFit.fill,
        );
      },
      onTap: (index) {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => MyWebViewPage(
                    title: _bannerList[index].title,
                    url: _bannerList[index].url)));
      },
    );
  }

  Widget _itemWidget(BuildContext context, int position) {
    return InkWell(
        onTap: () {
          Navigator.push(
              parentContext,
              MaterialPageRoute(
                  builder: (context) => MyWebViewPage(
                      title: _articleList[position - 1].title,
                      url: _articleList[position - 1].link)));
        },
        child: Container(
            padding: EdgeInsets.only(left: 20, right: 20, top: 10),
            child: Column(
              children: <Widget>[
                Container(
                    child: Row(
                  children: <Widget>[
                    Expanded(
                      child: Text(
                        _articleList[position - 1].author.isEmpty
                            ? ""
                            : _articleList[position - 1].author,
                        style:
                            TextStyle(color: Color(0xff666666), fontSize: 12),
                        textAlign: TextAlign.left,
                      ),
                    ),
                    Expanded(
                      child: Text(
                        _articleList[position - 1].niceDate.isEmpty
                            ? ""
                            : _articleList[position - 1].niceDate,
                        style:
                            TextStyle(color: Color(0xff666666), fontSize: 12),
                        textAlign: TextAlign.right,
                      ),
                    )
                  ],
                )),
                Container(
                    padding: EdgeInsets.only(top: 10, bottom: 10),
                    alignment: Alignment.centerLeft,
                    child: Text(
                      _articleList[position - 1].title.isEmpty
                          ? ""
                          : _articleList[position - 1].title,
                      style: TextStyle(
                          color: Color(0xff333333),
                          fontSize: 16,
                          fontWeight: FontWeight.w700),
                      textAlign: TextAlign.left,
                    )),
                Container(
                  alignment: Alignment.bottomLeft,
                  margin: EdgeInsets.only(bottom: 10),
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: Text(
                          _articleList[position - 1].superChapterName.isEmpty
                              ? ""
                              : _articleList[position - 1].superChapterName,
                          style:
                              TextStyle(color: Color(0xff666666), fontSize: 12),
                          textAlign: TextAlign.left,
                        ),
                      )
                    ],
                  ),
                ),
                Container(
                  height: 0.5,
                  alignment: Alignment.bottomCenter,
                  child: Divider(
                    color: Color(0xff00b7ee),
                  ),
                )
              ],
            )));
  }

  Widget _loadMoreWidget() {
    return Container(
      height: 50,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(right: 10),
            height: 20,
            width: 20,
            child: CircularProgressIndicator(
              strokeWidth: 2.0,
              backgroundColor: Colors.grey,
              // value: 0.2,
              valueColor: new AlwaysStoppedAnimation<Color>(Colors.grey),
            ),
          ),
          Container(
            child: Text("正在加载中...",
                style: TextStyle(color: Color(0xff666666), fontSize: 12)),
          )
        ],
      ),
    );
  }

  Widget _endWidget() {
    return Container(
      height: 50,
      child: Text(
        "---  我是有底线的  ---",
        style: TextStyle(color: Color(0xff666666), fontSize: 12),
      ),
    );
  }

  //加载banner网路数据
  Future<void> _getBannerData() async {
    NetService().getBanner((BannerModel bean) {
      if (bean != null && bean.data.length > 0) {
        setState(() {
          _bannerList = bean.data;
        });
      }
    });
  }

  //我是加载更多
  _getListData(int page) async {
    NetService().getArticleList((ArticleModel bean) {
      if (bean.data.datas.length < 20) {
        _hasMore = false;
      }
      setState(() {
        _articleList.addAll(bean.data.datas);
      });
    }, page);
  }
  //我是刷新数据
  Future<void> _getListRefreshData() async {
    NetService().getArticleList((ArticleModel bean) {
      setState(() {
        _articleList = bean.data.datas;
      });
    }, 0);
  }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值