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

Flutter如何实现点击按钮控制父Container高度展开收起

Flutter 可折叠展开容器实现方案

实现逻辑

核心通过状态变量控制容器高度切换,配合动画组件让高度变化更自然:

  • 用Stack布局实现右上角按钮悬浮在容器右上角的效果
  • 定义布尔状态值标记当前是展开/收起状态
  • 点击按钮时切换状态值,通过setState触发组件重建,动态修改容器高度参数
  • 用AnimatedContainer自带的动画过渡,避免高度切换生硬

完整可运行代码

import 'package:flutter/material.dart';

class ExpandableContainer extends StatefulWidget {
  // 支持外部自定义收起高度、背景色、内容组件、圆角
  final double collapsedHeight;
  final Widget child;
  final Color? backgroundColor;
  final double borderRadius;

  const ExpandableContainer({
    super.key,
    this.collapsedHeight = 100,
    required this.child,
    this.backgroundColor,
    this.borderRadius = 8,
  });

  @override
  State<ExpandableContainer> createState() => _ExpandableContainerState();
}

class _ExpandableContainerState extends State<ExpandableContainer> {
  // 初始默认收起状态
  bool _isExpanded = false;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // 动态切换高度的内容容器
        AnimatedContainer(
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeInOut,
          height: _isExpanded ? null : widget.collapsedHeight,
          width: double.infinity,
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
            color: widget.backgroundColor ?? Colors.white,
            borderRadius: BorderRadius.circular(widget.borderRadius),
            boxShadow: [
              BoxShadow(
                color: Colors.grey.withOpacity(0.2),
                blurRadius: 4,
                offset: const Offset(0, 2),
              )
            ],
          ),
          // 收起时裁剪超出内容,禁止内部滚动
          child: SingleChildScrollView(
            physics: const NeverScrollableScrollPhysics(),
            child: widget.child,
          ),
        ),
        // 右上角展开/收起控制按钮
        Positioned(
          top: 0,
          right: 0,
          child: IconButton(
            onPressed: () {
              setState(() {
                _isExpanded = !_isExpanded;
              });
            },
            icon: Icon(
              _isExpanded ? Icons.expand_less : Icons.expand_more,
              size: 28,
            ),
          ),
        )
      ],
    );
  }
}

// 组件调用示例
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('可展开容器示例')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: ExpandableContainer(
          collapsedHeight: 120,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: const [
              Text('标题内容', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
              SizedBox(height: 12),
              Text('这是一段测试长文本,用来演示容器收起和展开的效果,收起状态下只会展示固定高度内的内容,超出部分会被裁剪,点击右上角的展开按钮后,容器会自动过渡到适配内容的完整高度,再次点击按钮就会收回到初始的最小高度。你可以把任意自定义组件作为child传入,包括列表、图片、表单组件都能正常适配。'),
              SizedBox(height: 20),
              Text('其他补充内容', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
              SizedBox(height: 8),
              Text('1. 支持自定义收起时的固定高度\n2. 支持自定义容器背景色、圆角\n3. 自带300毫秒的平滑过渡动画\n4. 图标会跟随状态自动切换为向上/向下箭头'),
            ],
          ),
        ),
      ),
    );
  }
}

关键注意点

  • 收起状态下容器设置固定高度,超出内容会被自动裁剪,不需要额外处理内容溢出
  • 展开状态下将height设为null,容器会自动适配内部child的完整高度
  • 动画时长、曲线可以根据业务需求调整,不需要动画的话直接替换成普通Container即可
  • 如果内部内容本身是可滚动的(比如长列表),可以去掉外层的SingleChildScrollView,避免滑动冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 04:42:27