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

Flutter自定义可展开FAB子按钮点击无法触发路由跳转问题求助

问题原因

你的问题和回调类型、路由配置都无关,核心是两个布局逻辑的叠加导致点击事件无法触发:

  1. Transform 属于绘制阶段的变换,只会修改组件的渲染位置,不会调整组件的实际布局命中区域
  2. 你内层包裹按钮的Stack没有指定尺寸,默认会适配最大子元素的大小(也就是主FAB的60x60尺寸),所有通过Transform向上平移超出这个60x60范围的子FAB,点击位置都不在Stack的命中检测范围内,自然不会触发对应的点击回调。
解决方案

给内层Stack套上足够大的尺寸容器,让它覆盖所有子FAB展开后的区域即可,同时可以调整对齐方式更符合展开逻辑:

@override
Widget build(BuildContext context) {
  return Stack(
    children: [
      Positioned(
        right: 10,
        bottom: 10,
        // 新增SizedBox指定足够的宽高,覆盖所有子FAB展开范围
        child: SizedBox(
          width: 80, // 适配FAB宽度+左右点击余量
          height: 370, // 最大偏移300 + 主FAB高度60 + 顶部余量10
          child: Stack(
            alignment: Alignment.bottomCenter, // 改成底部居中对齐,适配向上展开的逻辑
            children: [
              // 原有4个子FAB的代码保持不变
              Transform.translate(
                offset: Offset.fromDirection(getRadiansFromDegree(270),
                    degOneTranslationAnimation.value * 75),
                child: Transform(
                  transform: Matrix4.rotationZ(
                      getRadiansFromDegree(rotationAnimation.value))
                    ..scale(degOneTranslationAnimation.value),
                  alignment: Alignment.center,
                  child: CircularButton(
                    color: Colors.red,
                    width: 50,
                    height: 50,
                    icon: Icon(
                      Icons.storefront,
                      color: Colors.white,
                    ),
                    onClick: () {
                      Navigator.of(context)
                          .pushNamed(RouteGenerator.marketPage);
                    },
                  ),
                ),
              ),
              // 剩余3个子FAB代码保持不变
              Transform.translate(
                offset: Offset.fromDirection(getRadiansFromDegree(270),
                    degOneTranslationAnimation.value * 150),
                child: Transform(
                  transform: Matrix4.rotationZ(
                      getRadiansFromDegree(rotationAnimation.value))
                    ..scale(degOneTranslationAnimation.value),
                  alignment: Alignment.center,
                  child: CircularButton(
                    color: Colors.red,
                    width: 50,
                    height: 50,
                    icon: Icon(
                      Icons.phone_android,
                      color: Colors.white,
                    ),
                    onClick: () {
                      Navigator.of(context)
                          .pushNamed(RouteGenerator.myShopPage);
                    },
                  ),
                ),
              ),
              Transform.translate(
                offset: Offset.fromDirection(getRadiansFromDegree(270),
                    degOneTranslationAnimation.value * 225),
                child: Transform(
                  transform: Matrix4.rotationZ(
                      getRadiansFromDegree(rotationAnimation.value))
                    ..scale(degOneTranslationAnimation.value),
                  alignment: Alignment.center,
                  child: CircularButton(
                    color: Colors.red,
                    width: 50,
                    height: 50,
                    icon: Icon(
                      Icons.bookmarks_outlined,
                      color: Colors.white,
                    ),
                    onClick: () {
                      Navigator.of(context)
                          .pushNamed(RouteGenerator.bookmarkPage);
                    },
                  ),
                ),
              ),
              Transform.translate(
                offset: Offset.fromDirection(getRadiansFromDegree(270),
                    degOneTranslationAnimation.value * 300),
                child: Transform(
                  transform: Matrix4.rotationZ(
                      getRadiansFromDegree(rotationAnimation.value))
                    ..scale(degOneTranslationAnimation.value),
                  alignment: Alignment.center,
                  child: CircularButton(
                    color: Colors.red,
                    width: 50,
                    height: 50,
                    icon: Icon(
                      Icons.manage_search,
                      color: Colors.white,
                    ),
                    onClick: () {
                      Navigator.of(context)
                          .pushNamed(RouteGenerator.searchPage);
                    },
                  ),
                ),
              ),
              // 原有主FAB代码保持不变
              Transform(
                transform: Matrix4.rotationZ(
                    getRadiansFromDegree(rotationAnimation.value)),
                alignment: Alignment.center,
                child: CircularButton(
                  color: Colors.red,
                  width: 60,
                  height: 60,
                  icon: Icon(
                    Icons.menu,
                    color: Colors.white,
                  ),
                  onClick: () {
                    if (animationController.isCompleted) {
                      animationController.reverse();
                    } else {
                      animationController.forward();
                    }
                  },
                ),
              ),
            ],
          ),
        ),
      )
    ],
  );
}
可选优化

你代码中定义的degTwoTranslationAnimation、degThreeTranslationAnimation两个动画变量没有实际使用,可以直接删除减少冗余代码。如果需要防止子FAB未完全展开时的误触,可以给所有子FAB套上IgnorePointer组件,当animationController.isCompleted为false时禁用点击即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 13:09:00