问题描述
我想为自定义画家画布中的线条画制作动画。到目前为止,我所能做的是在两个点处创建两个圆,然后在这两个点之间创建一条线。但是我不知道如何为线条设置动画,好像它是从一个点到另一个点一样。我尝试了一些东西,但是无法正常工作。如果您有任何想法,请检查代码并向我提出建议。
import 'package:Flutter/material.dart';
import 'dart:math' as math;
class ProgressMonitorAnimation extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ProgressMonitorAnimationState();
}
class _ProgressMonitorAnimationState extends State<ProgressMonitorAnimation> with TickerProviderStateMixin {
double _progress = 0.0;
Animation<double> animation;
@override
void initState() {
var controller = AnimationController(duration: Duration(milliseconds: 3000),vsync: this);
animation = Tween(begin: 1.0,end: 0.0).animate(controller)..addListener(() {
setState(() {
_progress = animation.value;
});
});
controller.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return Transform(
alignment: Alignment.center,transform: Matrix4.rotationX(math.pi),child: CustomPaint(
foregroundPainter: Progresspainter(_progress),),);
}
}
class Progresspainter extends CustomPainter {
double _progress;
Progresspainter(this._progress);
@override
void paint(Canvas canvas,Size size) {
final Paint circlePainter = Paint()..color = Colors.green;
final Paint linePainter = Paint()..color = Colors.black..strokeWidth = 4..strokeCap = strokeCap.round;
canvas.drawCircle(Offset(0.0,30.0 * 3),10.0,circlePainter);
canvas.drawCircle(Offset(15.0 * 2,80.0 * 3),circlePainter);
canvas.drawLine(Offset(0.0 / (_progress * 10),Offset((30.0 * 3) + (15.0) / (_progress * 15) * 2,(80.0 * 3) / (_progress * 15)),linePainter);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
解决方法
您可以使用Flutter Custom Painter进行以下操作。
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
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.black;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 4.0;
canvas.drawPath(path,paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
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;
}
class AnimatedPathDemo extends StatefulWidget {
@override
_AnimatedPathDemoState createState() => _AnimatedPathDemoState();
}
class _AnimatedPathDemoState extends State<AnimatedPathDemo>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Completer<GoogleMapController> _controllerMap = Completer();
static final CameraPosition _initialPosition = CameraPosition(
// target: LatLng(12.947437,77.685345),target: LatLng(7.8731,80.7718),zoom: 8,);
void _startAnimation() {
_controller.stop();
_controller.reset();
_controller.repeat(
period: Duration(seconds: 2),);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: const Text('Animated Paint')),body: Stack(
children: <Widget>[
GoogleMap(
// rotateGesturesEnabled: false,mapType: MapType.normal,compassEnabled: false,initialCameraPosition: _initialPosition,// polylines: _polylines,// markers: _markers,onMapCreated: (GoogleMapController controller) {
// controller.setMapStyle(Utils.mapStyles);
_controllerMap.complete(controller);
},),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();
}
}