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

Flutter实现3x3 GridView点击Container触发抖动并保持正方形

Flutter 3x3 GridView 正方形布局+点击抖动实现方案

核心实现思路

分为两个独立模块处理需求,互不耦合:

  • 正方形布局:通过GridView内置属性直接控制,无需额外计算
  • 点击抖动:给每个网格项单独绑定动画控制器,点击时触发局部动画

1. 正方形GridView配置

直接设置GridView的两个核心参数即可保证所有子项始终为正方形:

  • crossAxisCount: 3 指定3列布局
  • childAspectRatio: 1 强制所有子项宽高比为1:1,不管父容器宽度如何变化,子项都会自动适配为正方形
    示例代码段:
GridView.count(
  crossAxisCount: 3,
  childAspectRatio: 1,
  padding: const EdgeInsets.all(12),
  crossAxisSpacing: 8,
  mainAxisSpacing: 8,
  children: List.generate(9, (index) => GridItem(index: index)),
)

2. 点击抖动动画实现

把每个网格项封装为独立的StatefulWidget,每个组件单独持有动画控制器,避免互相干扰。抖动效果通过Transform.translate配合弹性曲线动画实现小幅偏移即可:
完整的GridItem组件代码:

import 'package:flutter/material.dart';

class GridItem extends StatefulWidget {
  final int index;
  const GridItem({super.key, required this.index});

  @override
  State<GridItem> createState() => _GridItemState();
}

class _GridItemState extends State<GridItem> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _shakeAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
    // 定义抖动偏移量,范围-4到4像素,可自行调整幅度
    _shakeAnimation = Tween<double>(begin: 0, end: 4).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.elasticIn,
      ),
    );
    // 动画结束后自动重置
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _controller.reset();
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _controller.forward();
        // 可在此处添加点击后的其他业务逻辑
      },
      child: AnimatedBuilder(
        animation: _shakeAnimation,
        builder: (context, child) {
          return Transform.translate(
            offset: Offset(_shakeAnimation.value * (DateTime.now().microsecond % 2 == 0 ? 1 : -1), 0),
            child: Container(
              decoration: BoxDecoration(
                color: Colors.blue[100 * ((widget.index % 9) + 1)],
                borderRadius: BorderRadius.circular(8),
              ),
              child: Center(
                child: Text('Item ${widget.index + 1}'),
              ),
            ),
          );
        },
      ),
    );
  }
}

效果说明

  • 不管窗口/父容器宽度怎么变化,GridView子项始终保持正方形,无需手动计算宽高
  • 点击任意子项只会触发当前子项的抖动动画,不会影响其他网格项
  • 抖动幅度、时长、抖动方向(可改成上下抖动,修改offset的dy参数即可)都可以自行调整参数修改

内容的提问来源于stack exchange,提问作者Ahmed AL-Dilli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:54:00