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

Flutter实现折叠状态下Sliver App Bar的颜色切换

实现带轮播的渐变切换SliverAppBar

核心实现思路

  • 用StatefulWidget监听滚动状态,动态控制背景样式与轮播的显示/隐藏
  • 不在SliverAppBar的title中嵌套AppBar,直接通过leading、actions实现logo和操作项,避免出现1px分割线
  • 利用ScrollController获取滚动偏移,计算SliverAppBar的展开比例,以此切换渐变/纯色背景
  • 轮播组件放在flexibleSpace区域,随滚动收起自动隐藏

修改后的完整代码

import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';

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

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

class _HomePageState extends State<HomePage> {
  final ScrollController _scrollController = ScrollController();
  double _expansionRatio = 1.0;
  final double _toolbarHeight = kToolbarHeight;
  final double _carouselHeight = 112;
  final double _topPadding = 38;

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

  void _onScroll() {
    final maxScroll = _scrollController.position.maxScrollExtent;
    final currentScroll = _scrollController.position.pixels;
    setState(() {
      _expansionRatio = 1.0 - (currentScroll / maxScroll).clamp(0.0, 1.0);
    });
  }

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

  @override
  Widget build(BuildContext context) {
    final expandedHeight = _toolbarHeight + _topPadding + _carouselHeight;

    return Scaffold(
      backgroundColor: Colors.white,
      body: CustomScrollView(
        controller: _scrollController,
        slivers: [
          SliverAppBar(
            leading: const Icon(Icons.menu, color: Colors.white), // 替换为你的Logo
            actions: const [
              Padding(
                padding: EdgeInsets.only(right: 16),
                child: Icon(Icons.search, color: Colors.white), // 操作项示例
              )
            ],
            title: const Text("Sliver App Bar Demo", style: TextStyle(color: Colors.white)),
            titleSpacing: 0,
            centerTitle: false,
            pinned: true,
            floating: false,
            expandedHeight: expandedHeight,
            elevation: 0,
            // 动态切换背景:展开时渐变,折叠时纯色
            backgroundColor: _expansionRatio > 0.01
                ? Colors.transparent
                : Colors.blue,
            surfaceTintColor: Colors.transparent,
            // 滚动时隐藏阴影
            shadowColor: _expansionRatio > 0.01 ? Colors.transparent : null,
            flexibleSpace: FlexibleSpaceBar(
              background: Container(
                decoration: BoxDecoration(
                  gradient: _expansionRatio > 0.01
                      ? const LinearGradient(
                          begin: Alignment.topCenter,
                          end: Alignment.bottomCenter,
                          colors: [Colors.blue, Colors.white],
                          stops: [0, 0.65],
                        )
                      : null,
                  color: _expansionRatio <= 0.01 ? Colors.blue : null,
                ),
                child: Column(
                  children: [
                    SizedBox(height: _toolbarHeight + _topPadding),
                    // 根据展开比例控制轮播的显示与隐藏
                    if (_expansionRatio > 0.01)
                      CarouselSlider(
                        items: [
                          Container(
                            decoration: BoxDecoration(
                              border: Border.all(color: Colors.red),
                            ),
                            height: _carouselHeight,
                            child: const Center(child: Text('Item 1')),
                          ),
                          Container(
                            decoration: BoxDecoration(
                              border: Border.all(color: Colors.red),
                            ),
                            height: _carouselHeight,
                            child: const Center(child: Text('Item 2')),
                          ),
                          Container(
                            decoration: BoxDecoration(
                              border: Border.all(color: Colors.red),
                            ),
                            height: _carouselHeight,
                            child: const Center(child: Text('Item 3')),
                          ),
                        ],
                        options: CarouselOptions(
                          height: _carouselHeight,
                          autoPlay: true,
                          enlargeCenterPage: true,
                          viewportFraction: 1.0,
                        ),
                      ),
                  ],
                ),
              ),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(title: Text('Item #$index')),
              childCount: 20,
            ),
          ),
        ],
      ),
    );
  }
}

关键细节说明

  1. 滚动状态监听:通过ScrollController监听滚动偏移,计算_expansionRatio(0=完全折叠,1=完全展开),以此作为UI切换的依据
  2. 背景平滑切换:利用_expansionRatio判断,展开时显示渐变背景,折叠时切换为纯色背景,同时通过shadowColor控制阴影的显示/隐藏,避免出现1px分割线
  3. 轮播组件控制:当_expansionRatio趋近于0时,隐藏轮播组件,实现滚动收起的效果
  4. 顶部操作栏优化:直接在SliverAppBar上配置leading、title、actions,替代嵌套AppBar的方式,彻底解决1px线的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 21:13:10