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

Flutter点击关闭按钮隐藏容器问题求助(附代码)

问题原因及解决方案

你的代码存在几个关键问题导致功能失效,要实现从左侧显示到右侧隐藏的滑动效果,需要针对性调整组件结构:

核心问题

  1. StatelessWidget无法维护状态:你使用的是StatelessWidget,但点击按钮需要更新组件状态,必须改为StatefulWidget才能实现状态变更。
  2. 赋值语法错误:onTap里的isTap == !isTap是比较操作而非赋值,且StatelessWidget中的final变量本身也不允许修改。
  3. 缺少动画实现:要实现滑动隐藏的过渡效果,需要结合动画组件与状态管理。

修改后的完整代码

import 'package:flutter/material.dart';
import '../../theme.dart';

class PencapaianBersamaSection extends StatefulWidget {
  const PencapaianBersamaSection({Key? key}) : super(key: key);

  @override
  State<PencapaianBersamaSection> createState() => _PencapaianBersamaSectionState();
}

class _PencapaianBersamaSectionState extends State<PencapaianBersamaSection> with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<Offset> _slideAnimation;
  bool _isVisible = true;

  @override
  void initState() {
    super.initState();
    // 初始化动画控制器,设置过渡时长
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
    // 定义从初始位置滑到右侧外的动画轨迹
    _slideAnimation = Tween<Offset>(
      begin: Offset.zero,
      end: const Offset(1, 0),
    ).animate(CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeInOut,
    ));
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  void _toggleVisibility() {
    setState(() {
      _isVisible = !_isVisible;
    });
    // 根据显示状态播放/反向播放动画
    _isVisible ? _animationController.reverse() : _animationController.forward();
  }

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _slideAnimation,
      // 动画过程中保持显示,结束后完全隐藏
      child: _isVisible || _animationController.isAnimating
          ? Container(
              padding: EdgeInsets.all(16),
              width: MediaQuery.of(context).size.width / 1.1,
              height: 148,
              decoration: BoxDecoration(
                color: whiteColor,
                borderRadius: BorderRadius.circular(16),
              ),
              child: Stack(
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'Pencapaian bersama',
                                style: grayText.copyWith(fontSize: 10),
                              ),
                              Text(
                                'Periode Agustus 2022',
                                style: blackText.copyWith(fontSize: 14),
                              ),
                              const SizedBox(height: 8),
                              Row(
                                children: [
                                  Container(
                                    width: 25,
                                    height: 24,
                                    decoration: BoxDecoration(
                                      image: DecorationImage(
                                        image: AssetImage('assets/images/proses/icon_recycle.png'),
                                        fit: BoxFit.cover,
                                      ),
                                    ),
                                  ),
                                  const SizedBox(width: 8),
                                  Text(
                                    '16%',
                                    style: blackText.copyWith(fontSize: 20, fontWeight: semiBold),
                                  ),
                                ],
                              ),
                              const SizedBox(height: 8),
                              Text(
                                'Penurunan dari periode sebelumnya',
                                style: grayText.copyWith(fontSize: 8),
                              ),
                              const SizedBox(height: 8),
                              Text(
                                'Selengkapnya',
                                style: lightBlueText.copyWith(fontSize: 10),
                              ),
                            ],
                          ),
                          Container(
                            width: 149,
                            height: 92,
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image: AssetImage('assets/images/proses/image_pencapaian.png'),
                                fit: BoxFit.cover,
                              ),
                            ),
                          ),
                        ],
                      )
                    ],
                  ),
                  // 简化关闭按钮布局
                  Align(
                    alignment: Alignment.topRight,
                    child: GestureDetector(
                      onTap: _toggleVisibility,
                      child: Container(
                        width: 16,
                        height: 16,
                        decoration: BoxDecoration(
                          image: DecorationImage(
                            image: AssetImage('assets/images/proses/icon_close.png'),
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            )
          : const SizedBox.shrink(),
    );
  }
}

修改说明

  • 切换为StatefulWidget,混入SingleTickerProviderStateMixin用于管理动画控制器。
  • 使用SlideTransition实现从左到右的滑动过渡,AnimationController控制动画时长与播放状态。
  • 点击关闭按钮时,通过_toggleVisibility方法切换显示状态,并同步控制动画播放方向。
  • 动画结束后,通过_isVisible状态完全隐藏组件,返回SizedBox.shrink()节省布局空间。
  • 优化关闭按钮布局为Align(alignment: Alignment.topRight),替代原有的Row+Spacer写法,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 16:10:29