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

点击Stack中小部件时如何平滑切换堆叠组件并实现缩放动画

Flutter Stack堆叠组件平滑切换效果实现

以下是完整可运行的实现代码,核心通过Flutter隐式动画实现平滑过渡,同时动态调整子组件顺序控制堆叠层级:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Stack堆叠切换效果')),
        body: const StackSwitchDemo(),
      ),
    );
  }
}

class StackSwitchDemo extends StatefulWidget {
  const StackSwitchDemo({super.key});

  @override
  State<StackSwitchDemo> createState() => _StackSwitchDemoState();
}

class _StackSwitchDemoState extends State<StackSwitchDemo> {
  // 记录第一个组件是否为放大状态
  bool _isFirstLarge = true;
  // 统一动画时长
  final Duration _animDuration = const Duration(milliseconds: 300);
  // 放大/缩小状态的尺寸
  final double _largeSize = 300;
  final double _smallSize = 150;

  @override
  Widget build(BuildContext context) {
    return Stack(children: _buildStackChildren());
  }

  List<Widget> _buildStackChildren() {
    final Widget widgetA = _buildStackItem(
      title: "Widget A",
      color: Colors.blueAccent,
      isLarge: _isFirstLarge,
      onTap: () {
        // 仅当前组件为缩小状态时点击才触发切换
        if (!_isFirstLarge) setState(() => _isFirstLarge = true);
      },
    );

    final Widget widgetB = _buildStackItem(
      title: "Widget B",
      color: Colors.orangeAccent,
      isLarge: !_isFirstLarge,
      onTap: () {
        if (_isFirstLarge) setState(() => _isFirstLarge = false);
      },
    );

    // 放大状态的组件放在列表末尾,保证堆叠层级更高不被遮挡
    return _isFirstLarge ? [widgetB, widgetA] : [widgetA, widgetB];
  }

  Widget _buildStackItem({
    required String title,
    required Color color,
    required bool isLarge,
    required VoidCallback onTap,
  }) {
    return AnimatedPositioned(
      duration: _animDuration,
      curve: Curves.easeInOut,
      // 放大组件固定在左上,缩小组件放在右下
      left: isLarge ? 20 : MediaQuery.of(context).size.width - _smallSize - 20,
      top: isLarge ? 20 : MediaQuery.of(context).size.height - _smallSize - 100,
      child: GestureDetector(
        onTap: onTap,
        child: AnimatedContainer(
          duration: _animDuration,
          curve: Curves.easeInOut,
          width: isLarge ? _largeSize : _smallSize,
          height: isLarge ? _largeSize : _smallSize,
          color: color,
          child: Center(
            child: Text(title, style: const TextStyle(color: Colors.white, fontSize: 24)),
          ),
        ),
      ),
    );
  }
}

实现关键点

  • 用AnimatedPositioned和AnimatedContainer组合实现位置、尺寸的同步平滑过渡,无需手动管理动画控制器
  • 仅缩小状态的组件可触发点击切换,避免无效状态更新
  • 动态调整Stack子组件列表顺序,无需额外设置层级属性即可同步变更堆叠顺序

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 22:54:01