颤动 ListView 滚动到索引不可用

Posted

技术标签:

【中文标题】颤动 ListView 滚动到索引不可用【英文标题】:flutter ListView scroll to index not available 【发布时间】:2019-05-31 01:39:56 【问题描述】:

我需要什么:

我想按某个索引滚动列表,我该怎么做。

我所知道的:

scrollToIndex 应该从第 n 个索引开始,但是我们如何滚动到任何索引?

【问题讨论】:

试试indexed_list_view。 查看我写的这篇文章:medium.com/@diegoveloper/… @JeromeEscalante 我已经检查了 indexex_list_view 但它是无限列表我的列表来自数据库并且大小将是动态的。 @diegoveloper 我也检查了你的帖子,但在我的情况下,列表项大小不固定。 你也可以试试这个:github.com/quire-io/scroll-to-index 【参考方案1】:

不幸的是,ListView 没有内置的 scrollToIndex() 函数方法。您必须开发自己的方法来测量该元素对 animateTo()jumpTo() 的偏移量,或者您可以搜索这些建议的解决方案/插件或从其他帖子中搜索,例如 Flutter: Scrolling to a widget in ListView

(自 2017 年以来,flutter/issues/12319 讨论了一般的 scrollToIndex 问题,但目前还没有计划)


但是有一种不同类型的 ListView 确实支持 scrollToIndex(Slashbin 提到过):

ScrollablePositionedList 依赖:scrollable_positioned_list

您的设置与 ListView 完全一样,并且工作方式相同,只是您现在可以访问 ItemScrollController:

jumpTo(index, alignment) scrollTo(index, alignment, duration, curve)

简化示例:

ItemScrollController _scrollController = ItemScrollController();

ScrollablePositionedList.builder(
  itemScrollController: _scrollController,
  itemCount: _myList.length,
  itemBuilder: (context, index) 
    return _myList[index];
  ,
)

_scrollController.scrollTo(index: 150, duration: Duration(seconds: 1));

(请注意,此库由 Google 开发,而非 Flutter 核心团队开发。)

【讨论】:

很棒的答案。虽然我注意到当index == item.length - 1 时,scrollController 的行为很有趣。可能是因为我用了BouncingScrollPhysics() ScrollablePositionedList 的缺点是它与增量滚动要求不兼容(例如响应向上/向下箭头键),因为它的 API 确实涉及偏移量(甚至是相对偏移量)。 但是我不能为ScrollablePositionedList设置控制器键,如果你想做更多的事情就不好了【参考方案2】:

ScrollablePositionedList 可以用于此。 https://github.com/google/flutter.widgets/tree/master/packages/scrollable_positioned_list

Pub link - https://pub.dev/packages/scrollable_positioned_list

final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionListener = ItemPositionsListener.create();

ScrollablePositionedList.builder(
  itemCount: 500,
  itemBuilder: (context, index) => Text('Item $index'),
  itemScrollController: itemScrollController,
  itemPositionsListener: itemPositionListener,
);

然后可以通过以下方式滚动到特定项目:

itemScrollController.scrollTo(
  index: 150,
  duration: Duration(seconds: 2),
  curve: Curves.easeInOutCubic);

【讨论】:

【参考方案3】:

使用scroll_to_index lib,这里滚动总是执行到第六个位置,如下面的硬编码

dependencies:
    scroll_to_index: ^1.0.6

代码片段:

class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

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


class _MyHomePageState extends State<MyHomePage> 
  final scrollDirection = Axis.vertical;

  AutoScrollController controller;
  List<List<int>> randomList;

  @override
  void initState() 
    super.initState();
    controller = AutoScrollController(
        viewportBoundaryGetter: () =>
            Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
        axis: scrollDirection);
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView(
        scrollDirection: scrollDirection,
        controller: controller,
        children: <Widget>[
          ...List.generate(20, (index) 
            return AutoScrollTag(
              key: ValueKey(index),
              controller: controller,
              index: index,
              child: Container(
                height: 100,
                color: Colors.red,
                margin: EdgeInsets.all(10),
                child: Center(child: Text('index: $index')),
              ),
              highlightColor: Colors.black.withOpacity(0.1),
            );
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _scrollToIndex,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  
  // Scroll listview to the sixth item of list, scrollling is dependent on this number
  Future _scrollToIndex() async 
    await controller.scrollToIndex(6, preferPosition: AutoScrollPosition.begin);
  

输出:

【讨论】:

【参考方案4】:

如果您知道 listview 项目大小,则滚动到首选索引很简单,例如:

var index = 15;
var widthOfItem =
176; //in dp. width needed for horizontallistView;
var heightOfItem =
200; //in dp. height need for vertical listView;
listViewScrollController.jumpTo(index * widthOfItem.toDouble());

listViewScrollController.animateTo(
index * widthOfItem.toDouble(),
duration: Duration(milliseconds: 500),
curve: Curves.ease);

【讨论】:

【参考方案5】:

找到一个 gist,其工作 gist url 是 https://gist.github.com/debuggerx01/b8ef756ee02b3eb82ec3702f14ba94e6

这个要点正在使用一个计算矩形大小的包。 https://pub.dartlang.org/packages/rect_getter

【讨论】:

是的,它可以工作,但看起来我的列表视图中带有 cmets 的 FPS 变得非常低.. 操作太多。 如果我使用 ListView.builder 是否可以使用此解决方案?

以上是关于颤动 ListView 滚动到索引不可用的主要内容,如果未能解决你的问题,请参考以下文章

颤动中滚动视图内的Listview

如何使我的 ListView 在颤动中可滚动?

一些滚动后颤动ListView KeepAlive

在颤动中加载项目后将Listview滚动到底部

在listview中颤动Custompaint:忽略两个手指滚动

Listview在颤动中强制滚动到顶部