Flutter:将项目添加到列表&后,Listview会获得全部滚动控制器的大小滚动到结束 [英] Flutter: Listview get full size of scrollcontroller after adding item to list & scroll to end

查看:149
本文介绍了Flutter:将项目添加到列表&后,Listview会获得全部滚动控制器的大小滚动到结束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇帖子描述了一个非常相似的问题,但是答案并不能解决所有问题:

This post describes a very similar problem, but the answer there doesn't solve all problems:

我有一个可能很长的列表,用户可以在其中添加新项目(一次打开).添加后/添加后,列表应滚动到末尾.

I have a potentially long List, where the user can add new items (on at a time). After/On add, the list should scroll to its end.

(顺便说一句,reverse: true不是选项)

(Btw no, reverse: true is not an option)

在阅读了另一篇文章之后,我理解使用SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd());应该可以欺骗b/c新列表maxScrollExtent是正确的.

After reading the other post, I understood using SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd()); should to the trick b/c the new lists maxScrollExtent will be correct.

但是它不能可靠地工作: 当已经滚动到列表的末尾或接近末尾时,一切正常. 但是,当在添加新项目时将列表滚动到其开头(或从末尾某种方式)时,该列表将被滚动,但是滚动位置恰好是一项-最新项.

But it doesn't work reliably: When already scrolled to the end of the list or near the end everything's ok. But when the list is scrolled to its start (or some way from the end) when adding a new item, the list gets scrolled, but the scrollposition is off by exactly one item - the newest one.

我认为这可能与ListView.builder不是让所有孩子都活着-而是如何解决有关?

I think it might have something to do with the ListView.builder not keeping all children alive - but how to solve it?

哦,还有一个额外的问题:刚刚发现了另一个非常奇怪的行为:在添加了两个项目之后,最后一个项目有点看不见了,但是列表不可滚动-这很奇怪.但是,甚至更奇怪的是,在下一个添加项上单击列表时,列表会滚动一小部分-但从未创建新项!?

Oh and bonus question: just discovered another very strange behaviour: after adding two items the last one is a little bit out of view but the list isn't scrollable - which is strange. But even stranger is that on the next add-item-click the list scrolls this tiny bit - but without ever creating the new item!?

下面是一个完整的示例:

Here a complete example:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

void main() {
  runApp(MyList());
}

class MyList extends StatefulWidget {
  MyList({Key key}) : super(key: key);

  @override
  _MyListState createState() => _MyListState();
}

var items = List<String>.generate(8, (i) => "Item $i");

class _MyListState extends State<MyList> {
  static ScrollController _scrollController = ScrollController();

  void add() {
    setState(() {
      items.add("new Item ${items.length}");
      print(items.length);
    });
    SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd());
  }

  void scrollToEnd() {
    _scrollController.animateTo(_scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 350), curve: Curves.easeOut);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "List",
      home: Scaffold(
          appBar: AppBar(
            title: Text("List"),
          ),
          body: ListView.builder(
            controller: _scrollController,
            itemCount: items.length,
            shrinkWrap: true,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('${items[index]}'),
              );
            },
          ),
          bottomSheet: Container(
              decoration: BoxDecoration(
                  border:
                      Border(top: BorderSide(color: Colors.black, width: 1))),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  FloatingActionButton(
                    onPressed: () {
                      add();
                    },
                    child: Icon(Icons.add),
                  )
                ],
              ))),
    );
  }
}

推荐答案

我将滚动条和Scrollable.ensureVisible组合到了maxScrollExtent,并且它们每个都修复了另一个缺陷.

I combined scroll to maxScrollExtent with Scrollable.ensureVisible and each of them fixed the flaws of the other.

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class MyList extends StatefulWidget {
  MyList({Key key}) : super(key: key);

  @override
  _MyListState createState() => _MyListState();
}

class _MyListState extends State<MyList> {
  final ScrollController _scrollController = ScrollController();
  final lastKey = GlobalKey();
  List<String> items;

  @override
  void initState() {
    super.initState();
    items = List<String>.generate(8, (i) => "Item $i");
  }

  void add() {
    setState(() {
      items.add("new Item ${items.length}");
    });
    SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd());
  }

  void scrollToEnd() async {
    await _scrollController.animateTo(
        _scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 350),
        curve: Curves.easeOut);
    Scrollable.ensureVisible(lastKey.currentContext);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: "List",
        home: Scaffold(
          body: ListView.builder(
            controller: _scrollController,
            itemCount: items.length,
            shrinkWrap: true,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('${items[index]}'),
                key: index == items.length - 1 ? lastKey : null,
              );
            },
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              add();
            },
            child: Icon(Icons.add),
          ),
        ));
  }
}

Scrollable.ensureVisible本身无法提供可见性(如果尚未创建该项目),但是当该项目非常接近时可以应对.

Scrollable.ensureVisible itself cannot provide visibility if the item has not yet been created, but copes with them when item is very close.

这篇关于Flutter:将项目添加到列表&amp;后,Listview会获得全部滚动控制器的大小滚动到结束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆