Flutter 滚动组件

Flutter 滚动控件

SingleChildScrollView

滚动组件,类似于Android中的ScrollView,只能接收一个子元素。

scrollDirection:滚动方向。

padding:设置内边距。

BouncingScrollPhysics:滚动到边界效果
    - ClampingScrollPhysics:类似安卓效果,会有微光显示。
    - BouncingScrollPhysics:类似ios效果,会有回弹。
    - NeverScrollableScrollPhysics:禁止滚动。
    - AlwaysScrollableScrollPhysics:可以滚动。

在这里插入图片描述

Scrollbar(
    child: Container(
        width: double.infinity,
        child: SingleChildScrollView(
            physics: BouncingScrollPhysics(),
            padding: EdgeInsets.all(10),
            child: Column(
                children:
                str.split("").map((e) => Text(e, textScaleFactor: 2)).toList(),
            ),
        ),
    ),
)

NotificationListener

可以监听ListView、NestedScrollView、GridView的滚动监听。

NotificationListener与ScrollController对比

  • NotificationListener可以在任意位置监听,并且携带的信息更多。
  • ScrollController只能和具体的滚动组件关联后才能监听,只能获取当前滚动位置。

ScrollNotification类里包含一个metrics属性,其类型是ScrollMetrics,包含一些信息:

var extentBefore = notification.metrics.extentBefore; //已滑出ViewPort顶部的长度,已滚动距离
var extentInside = notification.metrics.extentInside; //ViewPort内部长度,表示屏幕显示的列表部分的长度
var extentAfter = notification.metrics.extentAfter; //未划入ViewPort部分的长度
var pixels = notification.metrics.pixels; //当前滚动距离
var maxScrollExtent = notification.metrics.maxScrollExtent; //最大可滚动距离

在这里插入图片描述

class NotificationListenerPage extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
        return _NotificationListenerPageState();
    }
}

class _NotificationListenerPageState extends State<NotificationListenerPage> {
    String _progress = "0%";

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: Text("滚动监听")),
            body: Scrollbar(
                child: NotificationListener<ScrollNotification>(
                    onNotification: (ScrollNotification notification) {
                        double progress = notification.metrics.pixels /
                            notification.metrics.maxScrollExtent;
                        setState(() => _progress = "${(progress * 100).toInt()}%");
                        return false;
                    },
                    child: Stack(
                        alignment: Alignment.center,
                        children: [
                            ListView.builder(
                                itemCount: 100,
                                itemExtent: 50,
                                itemBuilder: (context, index) => ListTile(
                                    title: Text("$index"),
                                ),
                            ),
                            CircleAvatar(
                                radius: 30,
                                child: Text(_progress),
                                backgroundColor: Colors.transparent.withAlpha(200),
                            ),
                        ],
                    ),
                ),
            ),
        );
    }
}

AnimatedList

在这里插入图片描述

class AnimatedListPage extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
        return _AnimatedListPageState();
    }
}

class _AnimatedListPageState extends State<AnimatedListPage> {
    final _listKey = GlobalKey<AnimatedListState>();
    var data = <String>[];
    int counter = 5;

    @override
    void initState() {
        super.initState();
        for (int i = 0; i < counter; i++) {
            data.add("${i + 1}");
        }
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text("AnimatedList"),
                actions: [
                    IconButton(
                        icon: const Icon(Icons.add),
                        onPressed: () {
                            addItem();
                        },
                    ),
                ],
            ),
            body: AnimatedList(
                key: _listKey,
                initialItemCount: data.length,
                itemBuilder: (context, index, animation) {
                    return buildItem(context, index);
                },
            ),
        );
    }

    Widget buildItem(BuildContext context, int index) {
        String c = data[index];
        return ListTile(
            key: ValueKey(c),
            title: Text(c),
            trailing: IconButton(
                icon: const Icon(Icons.delete),
                onPressed: () {
                    deleteItem(context, index);
                },
            ),
        );
    }

    void addItem() {
        data.add("${++counter}");
        _listKey.currentState!.insertItem(data.length - 1);
    }

    void deleteItem(BuildContext context, int index) {
        _listKey.currentState!.removeItem(
            index,
            (BuildContext context, Animation<double> animation) {
                var item = buildItem(context, index);
                data.removeAt(index);
                return item;
            },
        );
    }
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Flutter滚动吸顶效果通常使用SliverAppBar和CustomScrollView组合来实现。 首先,我们需要在页面中添加一个CustomScrollView组件,它允许我们自定义滚动行为和视图。然后,在CustomScrollView中添加一个SliverAppBar组件,它将负责实现滚动吸顶的效果。 SliverAppBar组件有一个属性pinned,设置为true时,表示它会在滚动时保持固定在顶部。给SliverAppBar添加一个flexibleSpace属性,这个属性可以放入一个widget,通常用来展示一些背景图片或者标题文字。 接下来,我们需要在SliverAppBar下方添加一个SliverList组件,它会根据滚动的位置来动态调整子组件的显示位置。在SliverList中放入我们要滚动的内容。需要注意的是,如果内容过长,需要使用ListView组件进行包裹,以便提供滚动的能力。 在整个滚动效果实现的过程中,我们还可以使用SliverPersistentHeader组件,它可以创建一个固定高度的header部分,优化性能。 需要注意的是,滚动吸顶效果中,如果内容超出屏幕则可滚动,如果不超出屏幕则不可滚动,所以一定要设置正确的滚动区域。可以通过设置CustomScrollView的slivers属性,将SliverAppBar和SliverList包裹在一起。 通过上述步骤,我们可以实现滚动吸顶的效果。用户在滚动时,SliverAppBar会根据滚动位置自动进行展开和收缩。这种效果在很多移动应用的首页中都非常常见。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值