gpt4 book ai didi

flutter - 如何在 flutter 中为路径设置动画?

转载 作者:IT老高 更新时间:2023-10-28 12:37:49 26 4
gpt4 key购买 nike

我想实现这里看到的路径动画效果:

This animation (I couldn't include it because the gif is too big)

我只想实现 map 上的路径动画,我知道我需要使用堆叠,放置我的 map ,然后使用Painter来绘制这样的路径,但是我怎样才能动画呢?

最佳答案

我知道这个问题有一个公认的答案,但我想展示这个问题的替代解决方案。

首先,从单个点创建自定义路径对于以下情况不是最佳的:

  • 计算每个段的长度并非易事
  • 以较小的增量均匀地制作步骤动画既困难又耗费资源
  • 不适用于二次/贝塞尔线段

就像在旧的 Android 中一样 is this path tracing method , 非常相似的 PathMetrics 也是如此存在于 Flutter 中。

在这个问题的公认答案的基础上,这里有一种更通用的方法来为任何路径设置动画。


所以给定一个路径和一个动画百分比,我们需要提取从开始到那个百分比的路径:

Path createAnimatedPath(
Path originalPath,
double animationPercent,
) {
// ComputeMetrics can only be iterated once!
final totalLength = originalPath
.computeMetrics()
.fold(0.0, (double prev, PathMetric metric) => prev + metric.length);

final currentLength = totalLength * animationPercent;

return extractPathUntilLength(originalPath, currentLength);
}

所以现在我只需要提取一个路径直到给定长度(而不是百分比)。我们需要结合所有现有的路径,直到一定距离。然后将最后一个路径段的一部分添加到现有路径中。

这样做非常简单。

Path extractPathUntilLength(
Path originalPath,
double length,
) {
var currentLength = 0.0;

final path = new Path();

var metricsIterator = originalPath.computeMetrics().iterator;

while (metricsIterator.moveNext()) {
var metric = metricsIterator.current;

var nextLength = currentLength + metric.length;

final isLastSegment = nextLength > length;
if (isLastSegment) {
final remainingLength = length - currentLength;
final pathSegment = metric.extractPath(0.0, remainingLength);

path.addPath(pathSegment, Offset.zero);
break;
} else {
// There might be a more efficient way of extracting an entire path
final pathSegment = metric.extractPath(0.0, metric.length);
path.addPath(pathSegment, Offset.zero);
}

currentLength = nextLength;
}

return path;
}

整个示例所需的其余代码:

void main() => runApp(
new MaterialApp(
home: new AnimatedPathDemo(),
),
);

class AnimatedPathPainter extends CustomPainter {
final Animation<double> _animation;

AnimatedPathPainter(this._animation) : super(repaint: _animation);

Path _createAnyPath(Size size) {
return Path()
..moveTo(size.height / 4, size.height / 4)
..lineTo(size.height, size.width / 2)
..lineTo(size.height / 2, size.width)
..quadraticBezierTo(size.height / 2, 100, size.width, size.height);
}

@override
void paint(Canvas canvas, Size size) {
final animationPercent = this._animation.value;

print("Painting + ${animationPercent} - ${size}");

final path = createAnimatedPath(_createAnyPath(size), animationPercent);

final Paint paint = Paint();
paint.color = Colors.amberAccent;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 10.0;

canvas.drawPath(path, paint);
}

@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}

class AnimatedPathDemo extends StatefulWidget {
@override
_AnimatedPathDemoState createState() => _AnimatedPathDemoState();
}

class _AnimatedPathDemoState extends State<AnimatedPathDemo>
with SingleTickerProviderStateMixin {
AnimationController _controller;

void _startAnimation() {
_controller.stop();
_controller.reset();
_controller.repeat(
period: Duration(seconds: 5),
);
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: const Text('Animated Paint')),
body: SizedBox(
height: 300,
width: 300,
child: new CustomPaint(
painter: new AnimatedPathPainter(_controller),
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _startAnimation,
child: new Icon(Icons.play_arrow),
),
);
}

@override
void initState() {
super.initState();
_controller = new AnimationController(
vsync: this,
);
}

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

关于flutter - 如何在 flutter 中为路径设置动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50978603/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com