Flutter中如何检测ListView的滚动位置

Posted

技术标签:

【中文标题】Flutter中如何检测ListView的滚动位置【英文标题】:How to detect scroll position of ListView in Flutter 【发布时间】:2019-06-01 14:01:53 【问题描述】:

我正在使用ListView 小部件将项目显示为列表。在窗口三中,查看的项目必须将中间的项目放在中间。

那么如何在滚动停止时检测ListView 的位置?

如何检测 ListView 滚动停止?

【问题讨论】:

【参考方案1】:

我使用了 NotificationListener,它是一个小部件,用于侦听在树上冒泡的通知。然后使用ScrollEndNotification,表示滚动已停止。

对于滚动位置,我使用了_scrollController,该类型是ScrollController

NotificationListener(
  child: ListView(
    controller: _scrollController,
    children: ...
  ),
  onNotification: (t) 
    if (t is ScrollEndNotification) 
      print(_scrollController.position.pixels);
    
  ,
),

【讨论】:

您将这些代码放在哪里,在 ListView (ui) 中还是在 bloc 中? 孩子:新的 NotificationListener( 对于 2021 年的用户,有一种更短的方法可以做到这一点(见我的回答):)【参考方案2】:

我会说您可以通过

轻松检测滚动位置
@override
  void initState() 
    super.initState();

    _scrollController = ScrollController();
    _scrollController.addListener(() 
      var _currectScrollPosition = _scrollController.position.pixels;//this is the line
    );
  

但是如果你要在 addListener() 中调用 setState ;没关系,但这会导致重建整个构建(上下文)。对于动画来说,这不是一个好习惯。

我建议将您的滚动小部件分离成一个单独的 StatefulWidget ,然后通过调用获取该小部件的状态

  _yourScrollableWidgetKey.currentState?.controller.addListener(() 
      //code.......
      setState(() );
    );

注意:设置一个 GlobalKey,并分配给您的 StatFulWidget。

  final _yourScrollableWidgetKey = GlobalKey<_YourScrollAbleWidget>();
  StackedPositionedAnimated(
    key: _yourScrollableWidgetKey,
  ),

【讨论】:

【参考方案3】:

NotificationListener 现在接受一个使代码更短的类型参数:)

NotificationListener<ScrollEndNotification>(
  child: ListView(
    controller: _scrollController,
    children: ...
  ),
  onNotification: (notification) 
    print(_scrollController.position.pixels);
    // Return true to cancel the notification bubbling. Return false (or null) to
    // allow the notification to continue to be dispatched to further ancestors.
    return true;
  ,
),

【讨论】:

有了NotificationListener&lt;ScrollEndNotification&gt;,我相信除了打印像素之外,您不再需要_scrollController【参考方案4】:

除了@seddiq-sorush的回答,你可以将当前位置与_scrollController.position.maxScrollExtent比较,看看列表是否在底部

【讨论】:

【参考方案5】:

majidfathi69 的回答很好,但您不需要在列表中添加控制器: (如果您只想在滚动结束时收到通知,请将 ScrollUpdateNotification 更改为 ScrollEndNotification。)

NotificationListener<ScrollUpdateNotification>(
  child: ListView(
    children: ...
  ),
  onNotification: (notification) 
    //How many pixels scrolled from pervious frame
    print(notification.scrollDelta);

    //List scroll position
    print(notification.metrics.pixels);
  ,
),

【讨论】:

【参考方案6】:

您也可以通过以下步骤实现此功能

import 'package:flutter/material.dart';

class YourPage extends StatefulWidget 
  YourPage(Key key) : super(key: key);

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


class _YourPageState extends State<YourPage> 

  ScrollController _scrollController;
  double _scrollPosition;

 _scrollListener() 
  setState(() 
   _scrollPosition = _scrollController.position.pixels;
 );


@override
void initState() 
  _scrollController = ScrollController();
  _scrollController.addListener(_scrollListener);
  super.initState();


 @override
 Widget build(BuildContext context) 
  return Scaffold(
  appBar: AppBar(
    automaticallyImplyLeading: false,
    title: Text('Position $_scrollPosition pixels'),
  ),
  body: Container(
      child: ListView.builder(
    controller: _scrollController,
    itemCount: 200,
    itemBuilder: (context, index) 
      return ListTile(
        leading: Icon(Icons.mood),
        title: Text('Item: $index'),
      );
    ,
  )),
);


【讨论】:

【参考方案7】:

如果你想检测你的ListView的滚动位置,你可以简单地使用这个;

Scrollable.of(context).position.pixels

【讨论】:

如何检测 ListView 滚动停止?

以上是关于Flutter中如何检测ListView的滚动位置的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter 中使用 InheritedWidget 时 ListView 失去滚动位置

Flutter - ListView.builder:初始滚动位置

如何使用 Flutter 从 Firestore 中的 ListView 获得无限滚动

25.Flutter的ListView监听滚动事件之ScrollController

如何在 Flutter 中自动滚动 Listview.separated 中的所有 List Tiles?

Flutter Horizo​​ntal ListView - 如何“跳转”选定的索引