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

Flutter:实现带可折叠bottom的StatefulWidget版AppBar遇问题

解决Flutter可折叠Bottom的StatefulWidget版AppBar高度异常问题

问题根源

你封装的MyAppBar中,preferredSize是固定值,而控制bottom显示的expand状态仅存在于State类中。由于StatefulWidget的实例不可变,setState只会触发State的重建,无法更新Widget类的preferredSize,导致AppBar整体高度不随bottom的显隐变化,要么顶部栏上移、要么折叠后留空白。

解决方案

方案一:基于原生AppBar封装,让Widget响应状态变化

将控制状态的变量移到MyAppBar类中,用ValueNotifier监听变化,确保preferredSize能动态计算:

import 'package:flutter/material.dart';

class MyAppBar extends StatefulWidget implements PreferredSizeWidget {
  MyAppBar({Key? key}) : super(key: key);

  final ValueNotifier<bool> _expandNotifier = ValueNotifier(false);
  
  bool get expand => _expandNotifier.value;
  set expand(bool value) => _expandNotifier.value = value;

  @override
  Size get preferredSize => Size.fromHeight(
        kToolbarHeight + (expand ? kToolbarHeight : 0),
      );

  @override
  State<MyAppBar> createState() => MyAppBarState();
}

class MyAppBarState extends State<MyAppBar> {
  @override
  void initState() {
    super.initState();
    widget._expandNotifier.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    widget._expandNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: const Text("可折叠底部栏"),
      leading: IconButton(
        icon: Icon(widget.expand ? Icons.expand_less : Icons.expand_more),
        onPressed: () => widget.expand = !widget.expand,
      ),
      bottom: widget.expand
          ? PreferredSize(
              preferredSize: const Size.fromHeight(kToolbarHeight),
              child: Container(
                height: kToolbarHeight,
                color: Colors.blue[200],
                child: const Center(child: Text("底部栏内容")),
              ),
            )
          : null,
    );
  }
}

方案二:自定义AppBar结构,直接控制高度

不依赖原生AppBar,自己构建顶部栏和可折叠底部栏,直接通过State控制整体高度:

import 'package:flutter/material.dart';

class MyAppBar extends StatefulWidget implements PreferredSizeWidget {
  MyAppBar({Key? key}) : super(key: key);

  @override
  Size get preferredSize => _MyAppBarState.preferredSize;

  @override
  State<MyAppBar> createState() => _MyAppBarState();
}

class _MyAppBarState extends State<MyAppBar> {
  static Size preferredSize = Size.fromHeight(kToolbarHeight);
  bool expand = false;

  void _toggleExpand() {
    setState(() {
      expand = !expand;
      preferredSize = Size.fromHeight(
        kToolbarHeight + (expand ? kToolbarHeight : 0),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          height: kToolbarHeight,
          color: Theme.of(context).primaryColor,
          child: Row(
            children: [
              IconButton(
                icon: Icon(expand ? Icons.expand_less : Icons.expand_more),
                onPressed: _toggleExpand,
                color: Colors.white,
              ),
              const Text(
                "可折叠标题栏",
                style: TextStyle(color: Colors.white, fontSize: 18),
              ),
            ],
          ),
        ),
        if (expand)
          Container(
            height: kToolbarHeight,
            color: Theme.of(context).primaryColorLight,
            child: const Center(child: Text("底部栏内容")),
          ),
      ],
    );
  }
}

核心思路

确保PreferredSizeWidget的preferredSize能实时响应bottom的显隐状态:要么让Widget类能获取到控制状态,要么直接自定义布局来把控整体高度,避免原生AppBar的高度限制导致的布局异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:18:55