Flutter学习之滚动监听

Posted 隔壁小王66

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter学习之滚动监听相关的知识,希望对你有一定的参考价值。

ScrollController

构造方法

  ScrollController(
    double initialScrollOffset = 0.0,  //初始化滑动距离
    this.keepScrollOffset = true,//是否保存滑动距离
    this.debugLabel,
  ) : assert(initialScrollOffset != null),
       assert(keepScrollOffset != null),
       _initialScrollOffset = initialScrollOffset;
属性含义
initialScrollOffset初始化滑动距离
keepScrollOffset是否保存滑动距离,默认true

例如:

  ScrollController _scrollController = new ScrollController(initialScrollOffset: 1000);

设置初始化滑动距离为1000像素,打开页面时就已经滑动1000距离,不会触发监听

常用方法

方法含义
addListener滑动监听方法,在initState中监听
_scrollController.position.pixels滑动距离
_scrollController.offset滑动距离
_scrollController.position.maxScrollExtent最大可滑动距离,滑动组件内容长度
_scrollController.position.minScrollExtent最小可滑动距离,0
_scrollController.position.viewportDimension滑动视图所占长度
_scrollController.dispose()销毁监听,在dispose方法中调用
_scrollController.jumpTo控制滑动组件的滑动距离,无动画
_scrollController.animateTo(10);控制滑动组件的滑动距离,有动画
_scrollController.position.jumpTo同上
_scrollController.position.animateTo同上

ScrollPosition

ScrollController中包含一个ScrollPosition,里面包含的信息更加丰富,如果一个ScrollController监听多个滑动widget,可以用ScrollPosition加以区分

_scrollController.positions获取监听对象集合,然后取出各个监听的ScrollPosition,来获取滑动的一些信息
例如:_scrollController.positions.elementAt(0).pixels;

实现ScrollController滑动监听

class Scontroller extends State<Sc> 
  ScrollController _scrollController = new ScrollController();
  bool isShow = false;

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    _scrollController.addListener(() 
      int offset = _scrollController.position.pixels.toInt();
      print("滑动距离$offset");

      // 如果滑动到底部
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) 
        setState(() 
          isShow = true;
        );
       else 
        setState(() 
          isShow = false;
        );
      
    );
  

  @override
  void dispose() 
    // TODO: implement dispose
    _scrollController.dispose();
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("滑动控制"),
      ),
      body: Container(
        padding: EdgeInsets.all(20),
        child: Scrollbar(
            child: ListView.separated(
                physics: BouncingScrollPhysics(),
                controller: _scrollController,
                itemBuilder: (BuildContext buildContext, int index) 
                  return ListTile(
                    title: Text("标题"),
                    subtitle: Text("副标题$index"),
                    onTap: () 
                      print("$index");
                    ,
                  );
                ,
                separatorBuilder: (BuildContext buildContext, int index) 
                  return Divider(
                    color: Colors.grey,
                  );
                ,
                itemCount: 50)),
      ),
      floatingActionButton: !isShow
          ? null
          : FloatingActionButton(
              onPressed: () 
                _scrollController.position.jumpTo(10);
              ,
              child: Icon(Icons.arrow_upward),
            ),
    );
  

效果如下:

NotificationListener

NotificationListener是一个用来监听子widget滑动的widget
Flutter Widget树中子Widget可以通过发送通知(Notification)与父(包括祖先)Widget通信。父级组件可以通过NotificationListener组件来监听自己关注的通知

可滚动组件在滚动时会发送ScrollNotification类型的通知,ScrollBar正是通过监听滚动通知来实现的。通过NotificationListener监听滚动事件和通过ScrollController有两个主要的不同:

1、通过NotificationListener可以在从可滚动组件到widget树根之间任意位置都能监听。而ScrollController只能和具体的可滚动组件关联后才可以。
收到滚动事件后获得的信息不同;

2、NotificationListener在收到滚动事件时,通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController只能获取当前滚动位置。

实现例子:

class Scontroller1 extends State<Sc> 
  ScrollController _scrollController = new ScrollController(initialScrollOffset: 1000);
  bool isShow = false;
  String _progress = "0%";

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    _scrollController.addListener(() 
      int offset = _scrollController.position.viewportDimension.toInt();
      print("滑动距离$offset");

      // 如果滑动到底部
      if (_scrollController.offset ==
          _scrollController.position.maxScrollExtent) 
        setState(() 
          isShow = true;
        );
       else 
        setState(() 
          isShow = false;
        );
      
    );
  

  @override
  void dispose() 
    // TODO: implement dispose
    _scrollController.dispose();
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("滑动控制"),
      ),
      body: Container(
        padding: EdgeInsets.all(20),
        child: Stack(
          alignment: Alignment.center,
          children: <Widget>[
            Scrollbar(
              child: NotificationListener(
                  onNotification: (ScrollNotification notification) 
                    //滑动进度/最大可滑动进度
                    double progress = notification.metrics.pixels /
                        notification.metrics.maxScrollExtent;
                    setState(() 
                      _progress = "$((progress * 100).toInt())%";
                    );
                  ,
                  child: ListView.separated(
                      physics: BouncingScrollPhysics(),
                      controller: _scrollController,
                      itemBuilder: (BuildContext buildContext, int index) 
                        return ListTile(
                          title: Text("标题"),
                          subtitle: Text("副标题$index"),
                          onTap: () 
                            print("$index");
                          ,
                        );
                      ,
                      separatorBuilder: (BuildContext buildContext, int index) 
                        return Divider(
                          color: Colors.grey,
                        );
                      ,
                      itemCount: 50)),
            ),
            CircleAvatar(
              //显示进度百分比
              radius: 30.0,
              child: Text(_progress),
              backgroundColor: Colors.black54,
            ),
          ],
        ),
      ),
      floatingActionButton: !isShow
          ? null
          : FloatingActionButton(
              onPressed: () 
                _scrollController.jumpTo(10);
              ,
              child: Icon(Icons.arrow_upward),
            ),
    );
  


效果

使用方法

NotificationListener(
                  onNotification: (ScrollNotificati notification) 
                  //do something
                  ,
                  child:Widget
                  )

看一下ScrollNotification包含了什么

 ScrollNotification(
    @required this.metrics,
    @required this.context,
  );

metrics对象包含了什么

ScrollMetrics copyWith(
    double minScrollExtent,
    double maxScrollExtent,
    double pixels,
    double viewportDimension,
    AxisDirection axisDirection,
  )

ScrollNotification拿到的是一个包含滑动信息的对象

以上是关于Flutter学习之滚动监听的主要内容,如果未能解决你的问题,请参考以下文章

flutter学习之Listview

Flutter学习之混合开发

Flutter学习之混合开发

Flutter学习之测试

Flutter学习之测试

Flutter 学习之搭建环境