Flutter SliverAppBar实现下拉显示bar 上拉隐藏

转载请声明出处!!!

什么是SliverAppBar

SliverAppBar 类似于Android中的CollapsingToolbarLayout,可以轻松实现页面头部展开、合并的效果。 与AppBar大部分的属性重合,相当于AppBar的加强版

现在大部分app在一些页面都会有在用户在下拉页面的时候固定显示bar而在页面顶部的隐藏此部分,这个功能是可以用SliverAppBar和监听页面滚动来实现的

效果图:

首先创建一个ScrollController因为我们要用到CustomScrollView,在创建一个bool来判断是否要显示bar

添加监听页面滚动 判断的范围可以根据业务需求更改

ini 复制代码
void _onScroll() {
  // 获取当前滚动位置的偏移量
  final offset = _scrollController.offset;

  // 当滚动偏移量超过10,并且当前显示 AppBar 状态为 false 时,更新状态使 AppBar 显示
  if (offset > 10 && !showAppBar) {
    setState(() => showAppBar = true);
  }
  // 当滚动偏移量小于等于10,并且当前显示 AppBar 状态为 true 时,更新状态使 AppBar 隐藏
  else if (offset <= 10 && showAppBar) {
    setState(() => showAppBar = false);
  }
}

通过SliverLayoutBuilder来控制是否要显示SliverAppbar,SliverLayoutBuilder是一个可以在 Sliver 中动态构建 UI 的组件,允许你基于 SliverConstraints 动态调整 Sliver 布局。

less 复制代码
SliverLayoutBuilder(
  builder: (context, constraints) {
    return showAppBar
        ? SliverAppBar(
            pinned: true, //是否固定
            backgroundColor: Colors.white,
            elevation: 0,
            automaticallyImplyLeading: false,
            toolbarHeight: 43.h,
            flexibleSpace: FlexibleSpaceBar(
              collapseMode: CollapseMode.pin,
              background: _buildHeaderBar(),
            ),
          )
        : SliverToBoxAdapter(child: SizedBox.shrink());
  },
),

全部代码:

less 复制代码
class MySliverPage extends StatefulWidget {
  @override
  _MySliverPageState createState() => _MySliverPageState();
}

class _MySliverPageState extends State<MySliverPage> {
  final ScrollController _scrollController = ScrollController();
  bool showAppBar = false;

  void _onScroll() {
    // 获取当前滚动位置的偏移量
    final offset = _scrollController.offset;

    // 当滚动偏移量超过10,并且当前显示 AppBar 状态为 false 时,更新状态使 AppBar 显示
    if (offset > 10 && !showAppBar) {
      setState(() => showAppBar = true);
    }
    // 当滚动偏移量小于等于10,并且当前显示 AppBar 状态为 true 时,更新状态使 AppBar 隐藏
    else if (offset <= 10 && showAppBar) {
      setState(() => showAppBar = false);
    }
  }

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.removeListener(_onScroll);
    _scrollController.dispose();
    super.dispose();
  }

  Widget _buildHeaderBar() {
    return Column(
      children: [
        30.h.heightBox,
        Row(
          children: [
            15.w.widthBox,
            ClipRRect(
              borderRadius: BorderRadius.circular(15),
              child: SizedBox(
                width: 30.w,
                height: 30.w,
                child: CachedNetworkImage(
                  imageUrl: 'https://img2.baidu.com/it/u=3901868821,1751410039&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
                  fit: BoxFit.cover,
                ),
              ),
            ),
            10.w.widthBox,
            Text("lynxx", style: TextStyle(fontSize: 12.sp, color: Colors.black)),
            Spacer(),
            IconButton(
              onPressed: () {},
              icon: Icon(Icons.settings, color: Colors.black, size: 15),
            ),
          ],
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        controller: _scrollController,
        slivers: [
          // 通过 SliverLayoutBuilder 来控制是否插入 SliverAppBar
          SliverLayoutBuilder(
            builder: (context, constraints) {
              return showAppBar
                  ? SliverAppBar(
                      pinned: true, //是否固定
                      backgroundColor: Colors.white,
                      elevation: 0,
                      automaticallyImplyLeading: false,
                      toolbarHeight: 43.h,
                      flexibleSpace: FlexibleSpaceBar(
                        collapseMode: CollapseMode.pin,
                        background: _buildHeaderBar(),
                      ),
                    )
                  : SliverToBoxAdapter(child: SizedBox.shrink());
            },
          ),

          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(title: Text("Item $index")),
              childCount: 50,
            ),
          ),
        ],
      ),
    );
  }
}

觉得有帮助的点点赞😊

相关推荐
嘿嘿嘿呼呼嘿1 小时前
Riverpod源码分析1:Provider & ProviderFamily
flutter
zacksleo4 小时前
鸿蒙Flutter实战:20. Flutter集成高德地图,同层渲染
flutter·harmonyos
zacksleo4 小时前
鸿蒙Flutter实战:19-Flutter集成高德地图,跳转页面方式
flutter·harmonyos
A0微声z4 小时前
从0到1掌握Flutter(四)方法与类
flutter
嘿嘿嘿呼呼嘿5 小时前
Riverpod源码分析3:Provider的观察、刷新与销毁
flutter
嘿嘿嘿呼呼嘿5 小时前
Riverpod源码分析2:作用域 ProviderScope
flutter
小墙程序员6 小时前
Flutter 教程(四)包管理
flutter
sunly_8 小时前
Flutter:切换账号功能记录
android·java·flutter
getapi8 小时前
Flutter和React Native在开发app中,哪个对java开发工程师更适合
java·flutter·react native
恋猫de小郭9 小时前
Android 确定废弃「屏幕方向锁定」等 API ,如何让 App 适配大屏和 PC/XR 等场景
android·前端·flutter