温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Flutter中怎么利用listview实现下拉刷新上拉加载更多功能

发布时间:2021-08-05 18:03:19 来源:亿速云 阅读:182 作者:Leah 栏目:开发技术

这期内容当中小编将会给大家带来有关Flutter中怎么利用listview实现下拉刷新上拉加载更多功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。


下拉刷新

在Flutter中系统已经为我们提供了google material design的刷新功能 , 样式与原生Android一样.

我们可以使用RefreshIndicator组件来实现Flutter中的下拉刷新,下面们还是先来看下如何使用吧

RefreshIndicator

构造方法:

 const RefreshIndicator({
    Key key,
    @required this.child,
    this.displacement: 40.0,      //触发下拉刷新的距离
    @required this.onRefresh,     //下拉回调方法
    this.color,                   //进度指示器前景色 默认为系统主题色
    this.backgroundColor,         //背景色
    this.notificationPredicate: defaultScrollNotificationPredicate,
  })

然后我们看一下效果以及实现方式:

Flutter中怎么利用listview实现下拉刷新上拉加载更多功能

然后我们看一下代码:

class _MyHomePageState extends State<MyHomePage> {
  List list = new List(); //列表要展示的数据
 

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
  }

  /**
   * 初始化list数据 加延时模仿网络请求
   */
  Future getData() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list = List.generate(15, (i) => '哈喽,我是原始数据 $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: new Text(widget.title),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length,
        ),
      ),
    );
  }

  Widget _renderRow(BuildContext context, int index) {
    return ListTile(
      title: Text(list[index]),
    );
  }

  /**
   * 下拉刷新方法,为list重新赋值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈喽,我是新刷新的 $i');
      });
    });
  }
}

代码不复杂,我们一步步分析:

MyHomePage 只是返回一个State,这里省略了.

首先body里我们返回了一个RefreshIndicator,这个组件自带下拉回调,然后里面我们包裹了一个listview,

然后使用List.generate()方法来创建了一个长度为15的List,并把List里的值赋值给ListView Item中的ListTile。

下拉回调onRefresh 我们返回了一个改变list的方法 .

在上面的代码中我们使用_onRefresh()方法来处理下拉刷新的回调

/**
   * 下拉刷新方法,为list重新赋值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈喽,我是新刷新的 $i');
      });
    });
  }

其中 Future.delayed()方法可以选择延迟处理任务,这里我们假设网络的延迟是3秒.

这样一个简单的下拉刷新就实现了.

上拉加载更多

对于加载更多的组件在Flutter中是没有提供的,所以在这里我们就需要考虑如何实现的。

在ListView中有一个ScrollController属性,它就是专门来控制ListView滑动事件,在这里我们可以根据ListView的位置来判断是否滑动到了底部来做加载更多的处理。

在这里我们可以使用如下代码来判断ListView 是否滑动到了底部

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('滑动到了最底部');
        _getMore();
      }
    });
  }

_scrollController是我们初始化的ScrollController对象,通过监听我们可以判断现在的位置是否是最大的下滑位置来判断是否下滑到了底部。

看一下代码和效果:

Flutter中怎么利用listview实现下拉刷新上拉加载更多功能

class _MyHomePageState extends State<MyHomePage> {
  List list = new List(); //列表要展示的数据
  ScrollController _scrollController = ScrollController(); //listview的控制器
  int _page = 1; //加载的页数
  bool isLoading = false; //是否正在加载数据

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('滑动到了最底部');
        _getMore();
      }
    });
  }

  /**
   * 初始化list数据 加延时模仿网络请求
   */
  Future getData() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list = List.generate(15, (i) => '哈喽,我是原始数据 $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: new Text(widget.title),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length,
          controller: _scrollController,
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  Widget _renderRow(BuildContext context, int index) {
    return ListTile(
      title: Text(list[index]),
    );
  }

  /**
   * 下拉刷新方法,为list重新赋值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈喽,我是新刷新的 $i');
      });
    });
  }

  /**
   * 上拉加载更多
   */
  Future _getMore() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      await Future.delayed(Duration(seconds: 1), () {
        print('加载更多');
        setState(() {
          list.addAll(List.generate(5, (i) => '第$_page次上拉来的数据'));
          _page++;
          isLoading = false;
        });
      });
    }
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
  }
}

滑动到底部的时候,我们执行加载更多的方法,给list数据多加5条,这次我们把延迟改到了1秒:

/**
   * 上拉加载更多
   */
  Future _getMore() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      await Future.delayed(Duration(seconds: 1), () {
        print('加载更多');
        setState(() {
          list.addAll(List.generate(5, (i) => '第$_page次上拉来的数据'));
          _page++;
          isLoading = false;
        });
      });
    }
  }

是的,看着上面的效果我们已经实现了下拉加载更多,但是因为我们是滑动到底部触发的,如果在正在请求的过程中多次下拉就会造成多次加载更多的情况,所以我们还得对这个做下处理为了避免多次触发,我们加了一个isLoading,在上拉方法执行的过程中不会再次执行.

可以看到,我们仅仅在上面代码的基础上加上了一个isLoading的变量,当这个变量的值为true时,就不会触发加载更多的操作。

而因为是网络请求,可能需要分页,所以我们加了个page参数来查看是第几次触发上拉加载.

因为我们加了个监听,在组件卸载掉的时候记得移除这个监听,所以:

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
  }

这个一定不要忘记,养成好习惯,每次加了监听都跑到这个方法里移除掉.

这样,我们一个简单的上拉加载更多的功能就实现了.

但是还有个问题,没有用户交互啊,加载的时候要有个提示,于是我们尝试上拉的时候展示一个加载中的组件给用户:

首先我们创建加载更多时显示的Vidget

/**
   * 加载更多时显示的组件,给用户提示
   */
  Widget _getMoreWidget() {
    return Center(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Text(
              '加载中...     ',
              style: TextStyle(fontSize: 16.0),
            ),
            CircularProgressIndicator(strokeWidth: 1.0,)
          ],
        ),
      ),
    );
  }

然后我们在listview的itemcount那里把count+1,相当于我们给listview加了个尾部的组件.

 body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length + 1,   //这里!这里!这里!
          controller: _scrollController,
        ),

看一下效果是否满意:

Flutter中怎么利用listview实现下拉刷新上拉加载更多功能

嗯,基本符合要求,感觉那个刷新图标加的有点丑,画蛇添足了,不过功能都是ok了的.

当然, 大家可以根据自己的需要去自己实现想要的样式

看一下全部的代码:

/*
 * Created by 李卓原 on 2018/9/13.
 * email: zhuoyuan93@gmail.com
 *
 */
 
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List list = new List(); //列表要展示的数据
  ScrollController _scrollController = ScrollController(); //listview的控制器
  int _page = 1; //加载的页数
  bool isLoading = false; //是否正在加载数据

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('滑动到了最底部');
        _getMore();
      }
    });
  }

  /**
   * 初始化list数据 加延时模仿网络请求
   */
  Future getData() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list = List.generate(15, (i) => '哈喽,我是原始数据 $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: new Text(widget.title),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length + 1,
          controller: _scrollController,
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  Widget _renderRow(BuildContext context, int index) {
    if (index < list.length) {
      return ListTile(
        title: Text(list[index]),
      );
    }
    return _getMoreWidget();
  }

  /**
   * 下拉刷新方法,为list重新赋值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈喽,我是新刷新的 $i');
      });
    });
  }

  /**
   * 上拉加载更多
   */
  Future _getMore() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      await Future.delayed(Duration(seconds: 1), () {
        print('加载更多');
        setState(() {
          list.addAll(List.generate(5, (i) => '第$_page次上拉来的数据'));
          _page++;
          isLoading = false;
        });
      });
    }
  }

  /**
   * 加载更多时显示的组件,给用户提示
   */
  Widget _getMoreWidget() {
    return Center(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Text(
              '加载中...',
              style: TextStyle(fontSize: 16.0),
            ),
            CircularProgressIndicator(
              strokeWidth: 1.0,
            )
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
  }
}

上述就是小编为大家分享的Flutter中怎么利用listview实现下拉刷新上拉加载更多功能了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI