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拿到的是一个包含滑动信息的对象

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值