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

Jetpack Compose:如何实现面板的平滑部分折叠效果?

优化三状态面板的联动滑动动画方案

核心思路:放弃独立组件的AnimatedVisibility,改用整体位置/高度动画实现区域联动

方案1:AnimatedContainer + 固定高度控制(适合高度已知的场景)

通过AnimatedContainer动态修改面板总高度,让三个区域随整体高度变化同步滑动,避免单独组件动画的断层问题:

enum PanelState { collapsed, fullyExpanded, partiallyExpanded }

class TriStatePanel extends StatefulWidget {
  @override
  _TriStatePanelState createState() => _TriStatePanelState();
}

class _TriStatePanelState extends State<TriStatePanel> {
  PanelState _currentState = PanelState.collapsed;
  final double _topAreaHeight = 100;
  final double _middleAreaHeight = 150;
  final double _bottomAreaHeight = 200;

  double get _panelTotalHeight {
    switch (_currentState) {
      case PanelState.collapsed:
        return 0;
      case PanelState.fullyExpanded:
        return _topAreaHeight + _middleAreaHeight + _bottomAreaHeight;
      case PanelState.partiallyExpanded:
        return _middleAreaHeight;
    }
  }

  void _switchPanelState() {
    setState(() {
      switch (_currentState) {
        case PanelState.collapsed:
          _currentState = PanelState.fullyExpanded;
          break;
        case PanelState.fullyExpanded:
          _currentState = PanelState.partiallyExpanded;
          break;
        case PanelState.partiallyExpanded:
          _currentState = PanelState.fullyExpanded;
          break;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 按钮栏
        ElevatedButton(onPressed: _switchPanelState, child: Text('切换面板状态')),
        Expanded(
          child: Align(
            alignment: Alignment.bottomCenter,
            child: AnimatedContainer(
              duration: const Duration(milliseconds: 300),
              curve: Curves.easeInOut,
              height: _panelTotalHeight,
              width: double.infinity,
              child: Column(
                children: [
                  Container(height: _topAreaHeight, color: Colors.blue),
                  Container(height: _middleAreaHeight, color: Colors.green),
                  Container(height: _bottomAreaHeight, color: Colors.orange),
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
}

方案2:Stack + AnimatedPositioned 实现精细位置联动

将三个区域放入Stack,通过AnimatedPositioned控制整体垂直偏移,同时配合透明度动画处理顶部区域的隐藏,实现更贴近需求的"顶部区域隐藏在中间区域后方"效果:

class TriStatePanel extends StatefulWidget {
  @override
  _TriStatePanelState createState() => _TriStatePanelState();
}

class _TriStatePanelState extends State<TriStatePanel> {
  PanelState _currentState = PanelState.collapsed;
  final double _topH = 100;
  final double _middleH = 150;
  final double _bottomH = 200;

  double get _panelOffsetY {
    switch (_currentState) {
      case PanelState.collapsed:
        return _middleH + _bottomH;
      case PanelState.fullyExpanded:
        return 0;
      case PanelState.partiallyExpanded:
        return _topH;
    }
  }

  double get _topAreaOpacity => _currentState == PanelState.partiallyExpanded ? 0 : 1;
  double get _bottomAreaOpacity => _currentState == PanelState.partiallyExpanded ? 0 : 1;

  void _switchState() {
    setState(() {
      switch (_currentState) {
        case PanelState.collapsed:
          _currentState = PanelState.fullyExpanded;
          break;
        case PanelState.fullyExpanded:
          _currentState = PanelState.partiallyExpanded;
          break;
        case PanelState.partiallyExpanded:
          _currentState = PanelState.fullyExpanded;
          break;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(onPressed: _switchState, child: Text('切换状态')),
        Expanded(
          child: Stack(
            alignment: Alignment.bottomCenter,
            children: [
              // 底部区域
              AnimatedOpacity(
                duration: const Duration(milliseconds: 300),
                opacity: _bottomAreaOpacity,
                child: Container(height: _bottomH, color: Colors.orange),
              ),
              // 中间区域
              AnimatedPositioned(
                duration: const Duration(milliseconds: 300),
                curve: Curves.easeInOut,
                bottom: _panelOffsetY,
                left: 0,
                right: 0,
                child: Container(height: _middleH, color: Colors.green),
              ),
              // 顶部区域
              AnimatedOpacity(
                duration: const Duration(milliseconds: 300),
                opacity: _topAreaOpacity,
                child: AnimatedPositioned(
                  duration: const Duration(milliseconds: 300),
                  curve: Curves.easeInOut,
                  bottom: _panelOffsetY + _middleH,
                  left: 0,
                  right: 0,
                  child: Container(height: _topH, color: Colors.blue),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

关键优化说明

  1. 抛弃AnimatedVisibility的独立组件动画逻辑,改用整体高度/位置变化驱动所有区域同步运动,彻底解决动画衔接断层问题
  2. 用枚举统一管理面板状态,确保状态转换逻辑严谨,避免出现异常跳转
  3. 统一使用Curves.easeInOut动画曲线,让滑动过渡更符合自然交互体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 02:59:59