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

Flutter中实现PreferredSizeWidget的组件如何结合Obx响应更新preferredSize

解决方案

方案1:优先使用Flutter自带PreferredSize组件(最简实现)

不需要手动实现PreferredSizeWidget接口,直接将动态逻辑完全包裹在Obx内,每次状态变化时返回对应高度的PreferredSize组件,AppBar会自动读取最新的高度参数:

class BottomOfAppBar extends StatelessWidget {
  BottomOfAppBar({Key? key, required this.tabs}) : super(key: key);
  final List<Widget> tabs;
  final tabbarenable2 = Get.find<RxBool>(tag: 'tabbarenable');

  @override
  Widget build(BuildContext context) {
    return Obx(() => PreferredSize(
      preferredSize: tabbarenable2.value 
          ? const Size.fromHeight(28.0) 
          : const Size.fromHeight(0.0),
      child: ColoredBox(
        color: Colors.white,
        child: Column(
          children: [
            if (tabbarenable2.value)
              TabBar(
                labelColor: Colors.purple[100],
                indicatorColor: Colors.purple,
                isScrollable: true,
                labelPadding: const EdgeInsets.only(left: 8.0),
                tabs: tabs,
              )
            // 隐藏时用空占位组件代替Text即可
            else
              const SizedBox.shrink(),
          ],
        ),
      ),
    ));
  }
}

方案2:自定义PreferredSizeWidget配合状态监听

如果必须保留自定义PreferredSizeWidget的实现,可将组件改为Stateful,监听Rx变量变化主动触发组件刷新,让AppBar重新读取preferredSize:

class BottomOfAppBar extends StatefulWidget implements PreferredSizeWidget {
  const BottomOfAppBar({Key? key, required this.tabs}) : super(key: key);
  final List<Widget> tabs;

  @override
  State<BottomOfAppBar> createState() => _BottomOfAppBarState();

  @override
  Size get preferredSize => Get.find<RxBool>(tag: 'tabbarenable').value
      ? const Size.fromHeight(28.0)
      : const Size.fromHeight(0.0);
}

class _BottomOfAppBarState extends State<BottomOfAppBar> {
  final tabbarenable2 = Get.find<RxBool>(tag: 'tabbarenable');
  late Worker _statusListener;

  @override
  void initState() {
    super.initState();
    // 监听状态变化,触发组件刷新
    _statusListener = ever(tabbarenable2, (_) => setState(() {}));
  }

  @override
  void dispose() {
    // 销毁监听避免内存泄漏
    _statusListener.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Obx(() => Container(
      child: ColoredBox(
        color: Colors.white,
        child: Column(
          children: [
            tabbarenable2.value
                ? TabBar(
                    labelColor: Colors.purple[100],
                    indicatorColor: Colors.purple,
                    isScrollable: true,
                    labelPadding: const EdgeInsets.only(left: 8.0),
                    tabs: widget.tabs)
                : const SizedBox.shrink()
          ],
        ),
      ),
    ));
  }
}

原问题根因

AppBar仅在自身需要重新布局时才会读取bottom属性的preferredSize值,原写法中只有build返回的子树被Obx包裹,状态变化时仅刷新子控件,不会触发AppBar重新读取高度参数,因此高度不会跟随状态变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:45:03