You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何隐藏被其他组件遮挡的SliverAppBar部分内容?

解决 Netflix 风格 AppBar 文本遮挡裁剪问题

要实现文本被第一个固定 AppBar 遮挡部分消失的效果,我们需要通过自定义裁剪器结合滚动偏移量来动态裁剪文本内容。以下是修改后的完整代码:

import 'package:flutter/material.dart';

class TopClip extends CustomClipper<Rect> {
  final double clipAmount;

  TopClip(this.clipAmount);

  @override
  Rect getClip(Size size) {
    // 裁剪顶部指定高度的区域
    return Rect.fromLTWH(0, clipAmount, size.width, size.height - clipAmount);
  }

  @override
  bool shouldReclip(covariant TopClip oldClipper) {
    return oldClipper.clipAmount != clipAmount;
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double scrollOffset = 0.0;

  // 根据滚动偏移计算透明度,上限0.4
  double get opacity => scrollOffset / 100 > 0.4 ? 0.4 : scrollOffset / 100;

  @override
  Widget build(BuildContext context) {
    // 计算裁剪高度:滚动偏移超过40时开始裁剪,最大裁剪高度为文本近似高度20
    double clipAmount = scrollOffset > 40 ? scrollOffset - 40 : 0;
    clipAmount = clipAmount > 20 ? 20 : clipAmount;

    return Scaffold(
      backgroundColor: Colors.purple.shade100,
      body: SafeArea(
        child: Stack(
          children: [
            NotificationListener<ScrollUpdateNotification>(
              onNotification: (notification) {
                setState(() {
                  scrollOffset = notification.metrics.pixels;
                });
                return true;
              },
              child: CustomScrollView(
                slivers: [
                  SliverAppBar(
                    expandedHeight: 0,
                    pinned: true,
                    backgroundColor: Colors.black.withOpacity(opacity),
                    shadowColor: Colors.transparent,
                    title: const Text(
                      'Stacked Container',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 22.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    toolbarHeight: 60,
                  ),
                  SliverAppBar(
                    clipBehavior: Clip.none,
                    floating: true,
                    toolbarHeight: 25,
                    shadowColor: Colors.transparent,
                    backgroundColor: Colors.transparent,
                    bottom: PreferredSize(
                      preferredSize: const Size(double.infinity, 10),
                      child: ClipRect(
                        clipper: TopClip(clipAmount),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            const SizedBox(width: 15.0),
                            Opacity(
                              opacity: 1 - opacity,
                              child: const Text(
                                'Sliver AppBar',
                                style: TextStyle(
                                  fontSize: 20.0,
                                  color: Colors.green,
                                ),
                              ),
                            ),
                            const SizedBox(width: 15.0),
                          ],
                        ),
                      ),
                    ),
                  ),
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        ListView.builder(
                          itemCount: 10,
                          shrinkWrap: true,
                          physics: const NeverScrollableScrollPhysics(),
                          itemBuilder: (context, index) {
                            return Container(
                              margin: const EdgeInsets.fromLTRB(10.0, 20, 10, 10),
                              color: Colors.deepPurple,
                              height: 300,
                              width: double.infinity,
                            );
                          },
                        )
                      ],
                    ),
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

关键修改说明:

  1. 自定义裁剪器 TopClip:根据传入的裁剪高度,裁剪文本顶部的指定区域,实现被遮挡部分消失的效果。
  2. 滚动偏移跟踪:使用 scrollOffset 变量记录滚动位置,替代原有的单一透明度变量,同时用于计算裁剪高度。
  3. 动态裁剪计算:当滚动偏移超过40时开始裁剪文本,最大裁剪高度设为文本近似高度20,确保文本完全被遮挡时不再显示。
  4. ClipRect 包裹文本:将第二个 SliverAppBar 的文本内容用 ClipRect 包裹,应用自定义裁剪器实现动态裁剪。

内容的提问来源于stack exchange,提问作者Kartik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 04:02:32