美文网首页
4.滚动监听及控制

4.滚动监听及控制

作者: ankouyang | 来源:发表于2022-09-27 09:52 被阅读0次

在前几节中,我们介绍了Flutter中常用的可滚动组件,也说过可以用ScrollController来控制可滚动组件的滚动位置,本节先介绍一下ScrollController,然后以ListView为例,展示一下ScrollController的具体用法。最后,再介绍一下路由切换时如何来保存滚动位置。

1.ScrollController

ScrollController构造函数如下

ScrollController({
  double initialScrollOffset = 0.0, //初始滚动位置
  this.keepScrollOffset = true,//是否保存滚动位置
  ...
})

我们介绍一下ScrollController常用的属性和方法:

  • initialScrollOffset初始化位置设置
  //定义一个ScrollController,定义初始化位置为500
  ScrollController scrollController = ScrollController(initialScrollOffset:500);
initialScrollOffset初始化设置
  • offset:可滚动组件当前的滚动位置。
  • jumpTo(double offset)、animateTo(double offset,...):这两个方法用于跳转到指定的位置,它们不同之处在于,后者在跳转时会执行一个动画,而前者不会。


    jumpTo和animateTo区别

ScrollController还有一些属性和方法,我们将在后面原理部分解释

1.滚动监听
ScrollController间接继承自Listenable,我们可以根据ScrollController来监听滚动事件,如:

 //滚动监听
    scrollController.addListener(() {
      print(scrollController.offset); //打印滚动位置
      if (scrollController.offset < 1000 && showToTopBtn) {
       // TODO
        setState(() {
          //调用父组件传递的方法
          showToTopBtn = false;
        });
      } else if (scrollController.offset >= 1000 && showToTopBtn == false) {
        setState(() {
          //调用父组件传递的方法
          showToTopBtn = true;
        });
      }

    });

2.实例

import 'package:flutter/material.dart';
import 'package:flutter_os_china/constants/constants.dart';
class ListViewWidget extends StatefulWidget {
  const ListViewWidget({Key? key}) : super(key: key);
  @override
  State<ListViewWidget> createState() => _ListViewWidgetState();
}
class _ListViewWidgetState extends State<ListViewWidget> {
  //定义一个ScrollController
  ScrollController scrollController = ScrollController();
  bool showToTopBtn = false; //是否显示“返回到顶部”按钮
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //滚动监听
    scrollController.addListener(() {
      // scrollController.jumpTo(100);
      // scrollController.jumpTo(600);
      print(scrollController.offset); //打印滚动位置
      if (scrollController.offset < 1000 && showToTopBtn) {
        setState(() {
          //调用父组件传递的方法
          showToTopBtn = false;
        });
      } else if (scrollController.offset >= 1000 && showToTopBtn == false) {
        setState(() {
          //调用父组件传递的方法
          showToTopBtn = true;
        });
      }

    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
         appBar: AppBar(
           title: const  Text('ListView'),
         ),
         body: buildListViewSeparated(),
         floatingActionButton: showToTopBtn?FloatingActionButton(
           backgroundColor: AppColor.primaryColor,
           child:  const Icon(Icons.arrow_upward,color: Colors.white),
           onPressed: () {
             // scrollController.jumpTo(0.0);
             scrollController.animateTo(
                 0.0,
                 duration: const Duration(milliseconds: 200),//动画持续时间
                 curve: Curves.linear,//动画方式
             );
           },
         ):null

    );
  }

  // ListView.separated
  ListView buildListViewSeparated() {
    return ListView.separated(
           controller: scrollController,
           itemBuilder: (context,index){
             return ListTile(title: Text('$index'),trailing: const Icon(Icons.arrow_forward_ios),onTap: (){},);
           },
           separatorBuilder: (context,index){
             return index%2==0?const Divider(color: Colors.green):const Divider(color: Colors.blue);
           },
           itemCount: 100,
       );
  }

  // ListView.builder
  ListView buildListViewBuilder() {
    return ListView.builder(
           itemCount: 100,//这里demo设置为100
           itemExtent: 80.0,//强制高度为50
           itemBuilder:(context,index){
            return ListTile(title: Text('$index'),trailing: const Icon(Icons.arrow_forward_ios),onTap: (){},);
          });
  }
}

滚动距离大于1000的时候出现回到顶部的图标,点击回到顶部

3.滚动位置恢复

PageStorage是一个用于保存页面(路由)相关数据的组件,它并不会影响子树的UI外观,其实,PageStorage是一个功能型组件,它拥有一个存储桶(bucket),子树中的Widget可以通过指定不同的PageStorageKey来存储各自的数据或状态。
每次滚动结束,可滚动组件都会将滚动位置offset存储到PageStorage中,当可滚动组件重新创建时再恢复。如果ScrollController.keepScrollOffset为false,则滚动位置将不会被存储,可滚动组件重新创建时会使用ScrollController.initialScrollOffset;ScrollController.keepScrollOffset为true时,可滚动组件在第一次创建时,会滚动到initialScrollOffset处,因为这时还没有存储过滚动位置。在接下来的滚动中就会存储、恢复滚动位置,而initialScrollOffset会被忽略。

4.ViewPort及滚动位置等信息
位置信息都是通过 实例化ScrollController后,通过 scrollController.position获取相关位置信息,具体的位置信息有:(当前滚动位置等于最大可滚动长度的时候,这个时候可以下拉加载更多)

  • pixels:当前滚动位置。
  • maxScrollExtent:最大可滚动长度。
  • extentBefore:滑出ViewPort顶部的长度;此示例中相当于顶部滑出屏幕上方的列表长度。
  • extentInside:ViewPort内部长度;此示例中屏幕显示的列表部分的长度。
  • extentAfter:列表中未滑入ViewPort部分的长度;此示例中列表底部未显示到屏幕范围部分的长度。
  • atEdge:是否滑到了可滚动组件的边界(此示例中相当于列表顶或底部)

相关文章

网友评论

      本文标题:4.滚动监听及控制

      本文链接:https://www.haomeiwen.com/subject/ctubortx.html