Flutter、ListView、如何在ListView的顶部添加多个项目并使其不滚动到顶部

And*_*rey 6 dart flutter flutter-layout

当我在顶部添加一些项目时,ListView它会滚动到0索引上的顶部项目。但是我需要它保持与添加项目之前相同的位置。

例如,消息列表顶部的聊天历史分页,如果我打开任何信使(电报、WhatsApp 等),打开历史悠久的聊天并向下滚动下载历史。历史记录将添加到列表的顶部(一次来自服务器约 20 条消息),但列表将保持在相同位置(滚动时)。

ListView如果你添加到底部,Flutter 的行为就像这样,但如果你添加到顶部,它会跳转到第一个添加的项目。我想让它留下来。

Cop*_*oad 9

截屏:

在此处输入图片说明


由于您没有共享任何代码,我只是创建了一个简单的演示来展示您如何实现像消息应用程序一样的效果。代码非常简单易懂,我几乎到处都使用了注释。

代码(空安全):

class _MyPageState extends State<MyPage> {
  // Say you have total 100 messages, and you want to load 20 messages on each scroll.
  final int _totalMessages = 100, _loadInterval = 20;
  final double _loadingOffset = 20;
  late final List<String> _messages;
  bool _loading = false;
  final ScrollController _controller = ScrollController();

  @override
  void initState() {
    super.initState();

    // Initially, load only 20 messages.
    _messages = List.generate(20, (i) => 'Message   #${_totalMessages - i}');
    _controller.addListener(_scrollListener);
  }

  void _scrollListener() async {
    var max = _controller.position.maxScrollExtent;
    var offset = _controller.offset;

    // Reached at the top of the list, we should make _loading = true
    if (max - offset < _loadingOffset && !_loading) {
      _loading = true;

      // Load 20 more items (_loadInterval = 20) after a delay of 2 seconds
      await Future.delayed(Duration(seconds: 2));
      int lastItem = _totalMessages - _messages.length;
      for (int i = 1; i <= _loadInterval; i++) {
        int itemToAdd = lastItem - i;
        if (itemToAdd >= 0) _messages.add('Message   #$itemToAdd');
      }

      // Items are loaded successfully, make _loading = false
      setState(() {
        _loading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Messages')),
      body: ListView.builder(
        controller: _controller,
        reverse: true,
        itemCount: _messages.length + 1, // +1 to show progress indicator.
        itemBuilder: (context, index) {
          // All messages fetched. 
          if (index == _totalMessages) return Container();

          // Reached top of the list, show a progress indicator. 
          if (index == _messages.length) return Align(child: CircularProgressIndicator());

          // Show messages. 
          return ListTile(title: Text('${_messages[index]}'));
        },
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我有类似的问题,但仅设置 reverse : true 并不能解决问题,因为我的列表可以从顶部和底部增长。5天以来一直在挣扎,有什么建议吗? (4认同)
  • 是的!就是这样:反向:true;谢谢你!我可以在 12 小时内授予赏金。稍等一会 ;) (2认同)