Flutter之ListView实现自动滑动到底部

简介: Flutter之ListView实现自动滑动到底部

使用场景

在常见社交App中,发送消息或者接收到他人消息后,消息列表都会自动滑动到底部,不需要我们手动滑动,这样的用户体验好。

思路

ListView使用ScrollController来控制滑动,其中有jumpToanimateTo2个方法滑动到指定的位置。

/// packages/flutter/lib/src/widgets/scroll_controller.dart

void jumpTo(double value){
    assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
    for (final ScrollPosition position in List<ScrollPosition>.from(_positions))
      position.jumpTo(value);
}

Future<void> animateTo(
    double offset, {
      required Duration duration,
      required Curve curve,
    }) async {
    assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
    await Future.wait<void>(<Future<void>>[
      for (int i = 0; i < _positions.length; i += 1) _positions[i].animateTo(offset, duration: duration, curve: curve),
    ]);
}

看命名就能看出来,jumpTo不带动画效果,animateTo能设置滑动动画。

第一个参数valueoffset都是代表ListView中的指定位置。

ScrollPostion

那么应该传入哪个值才是代表ListView的底部呢?

通过ScrollController2个方法的源码发现最终调用的是_positionjumpToanimateTo方法。

_postion是一个ScrollPostionScrollPostion中有2个变量minScrollExtentmaxScrollExtent,分别代表滑动到顶部、底部的位置。

最终可以使用以下代码实现滑动到底部

scrollController.jumpTo(scrollController.position.maxScrollExtent);

实现

布局

首先我们来定义一个简单的聊天界面。一个ListView,一个输入框,一个发送消息的按钮。

/// 消息列表
List<String> _messages = ["在干嘛","吃饭了吗","想你了","早点睡"];
TextEditingController _textEditingController = TextEditingController();
ScrollController _scrollController = ScrollController();

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('女神'),
    ),
    body: Column(
      children: [
        Expanded(
          child: ListView.builder(
            controller: _scrollController,
            itemBuilder: (context, index) {
              return SizedBox(
                child: Center(child: Text(_messages[index])),
                height: 50,
              );
            },
            itemCount: _messages.length,
          ),
        ),
        Row(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: TextField(
                  controller: _textEditingController,
                  decoration: InputDecoration(
                    hintText: "请输入消息",
                  ),
                  textInputAction: TextInputAction.send,
                  onSubmitted: sendMessage,
                ),
              ),
            ),
            IconButton(
              onPressed: () {
                /// 发送消息
                sendMessage(_textEditingController.text.trim());
                /// 清除输入框中的内容
                _textEditingController.text = "";
              },
              icon: Icon(Icons.send),
            ),
          ],
        ),
        SizedBox(height: 5),
      ],
    ),
  );
}

滑动到底部

点击发送按钮时,获取输入框中的消息,添加到消息列表中,更新ui,然后滑动到底部。

void sendMessage(String message) {
  if (message.isEmpty) return;
  setState(() {
    _messages.add(message);
  });
  _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
}

问题

看起来没啥问题,但是运行发现,每次发送完消息后,列表并没有滑动到底部,而是滑动到了倒数第二次数据。

原因是执行滑动到底部的操作时,列表数据还没有更新,maxScrollExtent还是更新之前的值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pucOH0Q3-1631608253352)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/308f11e872644472b83f78760105e2f3~tplv-k3u1fbpfcp-watermark.image)]

解决方案

那么我们需要等待setState刷新列表之后,再执行滑动操作。

所以我们可以使用延迟执行方案。一般延迟时间设置300到500毫秒即可。

void sendMessage(String message) {
  if (message.isEmpty) return;
  setState(() {
    _messages.add(message);
  });
  /// 延迟500毫秒,再进行滑动
  Future.delayed(Duration(milliseconds: 500), () {
    _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
  });
}


ok!大功告成,下面是演示效果。


image.png

相关文章
|
前端开发 机器人 数据安全/隐私保护
Flutter笔记:手写并发布一个人机滑动验证码插件
写 Flutter 项目时,遇到需要滑块验证码功能。滑块验证码属于人机验证码的一种,看起来像是在一个图片中“挖去”了一块,然后通过用户手动操作滑块,让被“挖去”的部分移回来。由于我不想使用各种第三方模块,因此决定自己实现一个初版以后慢慢添砖加瓦。本文是对第一个版本的一点记录。
380 1
|
7月前
Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套
Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套 在 Flutter 中,ListView 和 PageView 是两个常用的控件,它们可以用于滑动展示大量内容的场景,且支持各种嵌套方式,本文将介绍其中的一些花式嵌套方式。
283 0
|
5月前
flutter- Row Column Expanded ListView
flutter- Row Column Expanded ListView
|
5月前
Flutter 列表学习(listview,gridview,ExpansionTile,ScrollController,RefreshIndicator)
Flutter 列表学习(listview,gridview,ExpansionTile,ScrollController,RefreshIndicator)
|
7月前
Flutter.源码分析.flutter/packages/flutter/lib/src/widgets/scroll_view.dart/ListView
Flutter.源码分析.flutter/packages/flutter/lib/src/widgets/scroll_view.dart/ListView
64 0
|
iOS开发 容器
重识Flutter 在不同的滑动列表场景,请选择合适的Slivers - part2
在Flutter中,碰到复杂的、不同的滑动业务场景,若是选择了一个合适的Slivers组件,那么我认为问题会变得简单!
重识Flutter 在不同的滑动列表场景,请选择合适的Slivers - part2
重识Flutter 用于解决复杂滑动视窗问题的Slivers - part1
在日常的开发工作中,仅仅使用ListView、ListView.builder等这样的滑动组件就能满足大部分的业务需求,但在碰到较为复杂的滑动页面时,我认为Slivers可以帮你更简单的实现。
重识Flutter  用于解决复杂滑动视窗问题的Slivers - part1
|
缓存
【布局 widget】Flutter ListView
ListView 是最常用的滚动 widget,也是布局 widget。它在滚动方向上一个接一个地显示它的 child。
257 0
【布局 widget】Flutter ListView
|
Java Android开发 iOS开发
Flutter(六)——多子元素组件:ListView,Scaffold,AppBar,Row,Column
Flutter(六)——多子元素组件:ListView,Scaffold,AppBar,Row,Column
372 1
flutter系列之:flutter中listview的高级用法
一般情况下,我们使用Listview的方式是构建要展示的item,然后将这些item传入ListView的构造函数即可,通常情况下这样做是够用了,但是不排除我们会有一些其他的特殊需求。 今天我们会来讲解一下ListView的一些高级用法。