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

Flutter滚动时SliverAppBar内按钮收缩但图标无变化的问题

问题解决方案

核心问题分析

SliverAppBar的flexibleSpace在滚动时会整体收缩,但内部的IconButton图标默认是固定尺寸,不会自动跟随滚动偏移缩放。我们可以通过监听滚动偏移量,结合GetX的状态管理来动态调整图标大小,实现同步收缩效果。

步骤1:创建GetX滚动状态控制器

这个控制器负责监听滚动事件、计算缩放比例,并维护状态供UI响应:

class ScrollScaleController extends GetxController {
  final scrollController = CustomScrollController();
  final scale = 1.0.obs;
  final expandedHeight = 120.0;

  @override
  void onInit() {
    super.onInit();
    scrollController.addListener(_updateScale);
  }

  void _updateScale() {
    final offset = scrollController.offset;
    // 计算从完全展开到完全收缩的缩放比例区间(可自行调整最小缩放值)
    if (offset <= 0) {
      scale.value = 1.0;
    } else if (offset >= expandedHeight) {
      scale.value = 0.5;
    } else {
      scale.value = 1.0 - (offset / expandedHeight) * 0.5;
    }
  }

  @override
  void onClose() {
    scrollController.dispose();
    super.onClose();
  }
}

步骤2:修改HomePage实现同步缩放

将CustomScrollView与控制器绑定,并用Obx监听缩放比例变化,通过Transform.scale动态调整图标大小:

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

  @override
  Widget build(BuildContext context) {
    final scrollCtrl = Get.put(ScrollScaleController());
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        backgroundColor: Colors.deepPurple,
      ),
      drawer: const Drawer(),
      backgroundColor: Colors.deepPurple,
      body: ScrollConfiguration(
        behavior: NoGlowBehavior(),
        child: CustomScrollView(
          controller: scrollCtrl.scrollController,
          slivers: [
            SliverAppBar(
              toolbarHeight: 0.0,
              pinned: false,
              snap: true,
              floating: true,
              expandedHeight: scrollCtrl.expandedHeight,
              backgroundColor: const Color(0xFF2e2e2e),
              flexibleSpace: Stack(
                alignment: Alignment.center,
                children: [
                  Padding(
                    padding: const EdgeInsets.only(bottom: 50.0),
                    child: Container(color: Colors.deepPurple),
                  ),
                  Column(
                    children: [
                      Expanded(
                        flex: 4,
                        child: Padding(
                          padding: const EdgeInsets.symmetric(horizontal: 16.0),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: const [Text(''), Text('')],
                          ),
                        ),
                      ),
                      Expanded(
                        flex: 6,
                        child: Row(
                          children: [
                            const SizedBox(width: 16.0),
                            Expanded(
                              child: Card(
                                child: Obx(() => Transform.scale(
                                      scale: scrollCtrl.scale.value,
                                      child: IconButton(
                                        icon: const Icon(Icons.push_pin),
                                        onPressed: () {},
                                      ),
                                    )),
                              ),
                            ),
                            const SizedBox(width: 20.0),
                            Expanded(
                              child: Card(
                                child: Obx(() => Transform.scale(
                                      scale: scrollCtrl.scale.value,
                                      child: IconButton(
                                        icon: const Icon(Icons.add),
                                        onPressed: () {},
                                      ),
                                    )),
                              ),
                            ),
                            const SizedBox(width: 16.0)
                          ],
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            // 优化:移除嵌套ListView,改用纯Sliver组件实现列表
            SliverPadding(
              padding: const EdgeInsets.symmetric(horizontal: 20.0),
              sliver: SliverList(
                delegate: SliverChildBuilderDelegate(
                  (context, index) {
                    return Column(
                      children: [
                        Container(color: Colors.red, height: 100.0),
                        const SizedBox(height: 10.0),
                      ],
                    );
                  },
                  childCount: 10,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

原理说明

  1. 通过CustomScrollController监听滚动偏移量,计算出当前SliverAppBar的收缩比例
  2. 用GetX的obs变量维护缩放比例,Obx自动监听状态变化并更新UI
  3. Transform.scale根据实时计算的缩放值调整图标大小,实现与SliverAppBar的同步收缩

内容的提问来源于stack exchange,提问作者Héctor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:09:26