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

如何在Flutter中实现沿矩形路径的匀速Widget动画?

矩形路径匀速等间距容器动画解决方案

核心问题分析

直接用AnimationController的线性进度驱动矩形路径动画时,因为矩形四条边长度不同,相同进度增量对应的实际移动距离不一致,导致速度不均;同时如果直接按进度等分位置,会因边的长度差异造成容器间距不统一。

实现步骤

  • 计算矩形路径参数:先确定矩形的宽rectWidth、高rectHeight,算出总周长totalLength = 2 * (rectWidth + rectHeight),再明确每条边的长度及占周长的比例:
    • 上边长度:rectWidth,占比rectWidth / totalLength
    • 右边长度:rectHeight,占比rectHeight / totalLength
    • 下边长度:rectWidth,占比rectWidth / totalLength
    • 左边长度:rectHeight,占比rectHeight / totalLength
  • 进度转路径距离:将AnimationController的线性进度value(0-1区间)转换为实际路径上的移动距离distance = value * totalLength,确保进度变化对应的移动距离均匀,实现匀速效果。
  • 坐标计算逻辑:根据distance所在区间,判断容器处于哪条边,再计算对应坐标:
    1. 上边:distance <= rectWidth → x从0到rectWidth,y固定为0
    2. 右边:rectWidth < distance <= rectWidth + rectHeight → x固定为rectWidth,y从0到rectHeight
    3. 下边:rectWidth+rectHeight < distance <= 2*rectWidth + rectHeight → x从rectWidth到0,y固定为rectHeight
    4. 左边:2*rectWidth+rectHeight < distance <= totalLength → x固定为0,y从rectHeight到0
  • 多容器等间距处理:给每个容器的进度加上1 / 容器总数的偏移量(取模1保证循环),让每个容器在路径上的距离差为totalLength / 容器总数,实现均匀间距。

代码示例

import 'package:flutter/material.dart';

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

  @override
  State<RectPathAnimation> createState() => _RectPathAnimationState();
}

class _RectPathAnimationState extends State<RectPathAnimation> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  final int _containerCount = 4;
  final double _rectWidth = 300;
  final double _rectHeight = 200;
  late double _totalLength;

  @override
  void initState() {
    super.initState();
    _totalLength = 2 * (_rectWidth + _rectHeight);
    _controller = AnimationController(
      duration: const Duration(seconds: 4),
      vsync: this,
    )..repeat();
  }

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

  Offset _getContainerOffset(double progressOffset) {
    final double adjustedProgress = (_controller.value + progressOffset) % 1;
    final double distance = adjustedProgress * _totalLength;

    if (distance <= _rectWidth) {
      // 上边路径
      return Offset(distance, 0);
    } else if (distance <= _rectWidth + _rectHeight) {
      // 右边路径
      final double y = distance - _rectWidth;
      return Offset(_rectWidth, y);
    } else if (distance <= 2 * _rectWidth + _rectHeight) {
      // 下边路径
      final double x = _rectWidth - (distance - _rectWidth - _rectHeight);
      return Offset(x, _rectHeight);
    } else {
      // 左边路径
      final double y = _rectHeight - (distance - 2 * _rectWidth - _rectHeight);
      return Offset(0, y);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Stack(
          alignment: Alignment.center,
          children: [
            // 矩形路径参考框
            Container(
              width: _rectWidth,
              height: _rectHeight,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.grey, width: 2),
              ),
            ),
            // 动画容器组
            AnimatedBuilder(
              animation: _controller,
              builder: (context, child) {
                return Stack(
                  children: List.generate(_containerCount, (index) {
                    final progressOffset = index / _containerCount;
                    final offset = _getContainerOffset(progressOffset);
                    return Positioned(
                      left: offset.dx,
                      top: offset.dy,
                      child: Container(
                        width: 20,
                        height: 20,
                        decoration: const BoxDecoration(
                          color: Colors.blue,
                          shape: BoxShape.circle,
                        ),
                      ),
                    );
                  }),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

关键说明

  • 通过adjustedProgress = (_controller.value + progressOffset) % 1实现容器的循环偏移,确保间距始终均匀。
  • 进度转路径距离的逻辑,保证容器在矩形各边上的移动速度一致。
  • 可通过修改_controller的duration调整整体动画速度,修改_containerCount、_rectWidth、_rectHeight适配不同场景需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:42:51