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

Flutter页面跳转时Hero动画未正常工作问题求助

Flutter Hero组件无平滑转场动画问题排查与解决

问题根源

你的Hero组件被嵌套在Transform.scale和Transform.translate组件内部,这两个变换组件会修改子组件的渲染位置与尺寸,但Hero动画的过渡计算依赖组件的原始布局边界信息,变换后的组件无法被Hero正确捕获初始状态,导致转场时直接弹出目标页面,无平滑动画。

解决步骤

  1. 将Hero组件提升为PageView item的直接父节点,让Transform成为Hero的子节点(即Hero包裹Transform,而非反过来),确保Hero能获取到正确的布局基准。
  2. 保留PageView的缩放、平移效果,但将变换逻辑移至Hero内部的子树中。
  3. 确保_currentPage值能随PageController滚动正确更新(你的代码中未显示监听逻辑,这会导致缩放/平移效果无法实时更新)。

修改后的核心代码示例

// 先添加PageController监听(在initState中)
@override
void initState() {
  super.initState();
  _pageController.addListener(() {
    setState(() {
      _currentPage = _pageController.page!;
    });
  });
}

Widget buildSession() {
  List<Map<String, String>> tagesplan =
      gruppenTagesplan[_formatDate(widget.dataHolder.data)] ?? [];

  return PageView.builder(
    controller: _pageController,
    scrollDirection: Axis.horizontal,
    itemCount: tagesplan.length,
    itemBuilder: (context, index) {
      final cardData = tagesplan[index];
      double relativePosition = (index - _currentPage).abs();
      double scale = 0.8 + 0.2 * (1 - relativePosition);
      bool isSelected = relativePosition < 0.5;
      double position = -30 + relativePosition * -20.0;

      // 将Hero作为最外层组件,包裹Transform
      return Hero(
        tag: 'session_${cardData["start"]}-${cardData["end"]}',
        child: Transform.scale(
          scale: scale,
          child: Transform.translate(
            offset: Offset(position, 0.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const SizedBox(height: 4),
                Row(
                  children: [
                    const Spacer(),
                    Container(
                      alignment: Alignment.topLeft,
                      child: AnimatedOpacity(
                        opacity: isSelected ? 1.0 : 0.0,
                        duration: const Duration(milliseconds: 500),
                        child: Text(
                          "${cardData["start"]}-${cardData["end"]}",
                          style: const TextStyle(
                            fontWeight: FontWeight.bold,
                            fontSize: 26,
                            color: Colors.black,
                          ),
                        ),
                      ),
                    ),
                    const Spacer(),
                    const Spacer(),
                    const Spacer(),
                    const Spacer(),
                  ],
                ),
                const SizedBox(height: 8),
                GestureDetector(
                  onTap: () => _gotoDetailsPage(context, cardData),
                  child: Card(
                    elevation: 4.0,
                    color: const Color(0xff6d9773),
                    child: Container(
                      height: 400,
                      alignment: Alignment.center,
                      padding: const EdgeInsets.all(16.0),
                    ),
                  ),
                ),
                AnimatedOpacity(
                  opacity: isSelected ? 1.0 : 0.0,
                  duration: const Duration(milliseconds: 500),
                  child: const Text(
                    "More information here...",
                    style: TextStyle(fontSize: 16.0),
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    },
  );
}

额外排查要点

  • 测试移除所有Transform组件后,Hero转场是否正常,以此确认变换组件是问题核心。
  • 确保源页面和目标页面的Hero标签完全一致(你已确认此点,可忽略)。
  • 避免在Hero的父节点中使用任何会修改布局变换的组件(如Transform、ClipPath等),Hero需处于正常的布局流中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:35:27