首先,请多多注意我的问题;
我想通过startClickPosition&endPosition来创建Bezier路径,并绘制一个圆圈。
在代码中,我使用_path.computeMetrics()并获取PathMetrics,然后使用pms.elementAt(0)来获取PathMetric,但是我发现pms.length为0时出错。我的代码是:
Path getPath(){
Path path = Path();
path.moveTo(widget.startOffset.dx, widget.startOffset.dy);
// i'm ensure this 4 var got value and is right value,below this line.
double startX = widget.endOffset.dx / 2;
double startY = widget.startOffset.dy;
double endX = widget.endOffset.dx;
double endY = widget.endOffset.dy;
path.quadraticBezierTo(startX,startY,endX ,endY);
return path;
}
startAnimation(){
_path = getPath();
if(_path == null) print("path is null");
PathMetrics pms = _path.computeMetrics(forceClosed: false);
// here pms.length is always 0;
PathMetric pm = pms.elementAt(0);
double pathLen = pm.length;
_animation = Tween(begin: 0.0,end: pathLen).animate(_controller)
..addListener((){
setState(() {
_fraction = _animation.value;
print("fraction _____ $_fraction");
});
})
..addStatusListener((status){
if(status == AnimationStatus.completed){
_controller.stop();
}
});
_controller.forward();
}
非常感谢。 :)
整个代码:
class ParabolaAnimation extends StatefulWidget{
Size screenSize;
Offset startOffset;
Offset endOffset;
ParabolaAnimation(this.startOffset,this.endOffset,this.screenSize);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return ParabolaAnimationState();
}
}
class ParabolaAnimationState extends State<ParabolaAnimation> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
double _fraction = 0.0;
int _seconds = 3;
Path _path;
GlobalKey _key = GlobalKey();
@override
void initState() {
// TODO: implement initState
_controller = AnimationController(vsync: this,duration: Duration(seconds: _seconds));
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
WidgetsBinding.instance.addPostFrameCallback((_){
startAnimation();
});
return CustomPaint(
painter: PathPainter(_path, _fraction),
// child: Container(
// width: widget.screenSize.width,
// height: widget.screenSize.height,
// ),
);
}
startAnimation(){
_path = getPath();
print("path ${_path.toString()} ___ ");
if(_path == null) print("path is null");
PathMetrics pms = _path.computeMetrics(forceClosed: false);
if(pms.length == 0) return;
int plen = pms.length;
//only one path
PathMetric pm = pms.elementAt(0);
double pathLen = pm.length;
print("path len : $pathLen");
_animation = Tween(begin: 0.0,end: pathLen).animate(_controller)
..addListener((){
setState(() {
_fraction = _animation.value;
print("fraction _____ $_fraction");
});
})
..addStatusListener((status){
if(status == AnimationStatus.completed){
_controller.stop();
}
});
_controller.forward();
}
Path getPath(){
print("start offset ${widget.startOffset.toString()}");
print("end offset ${widget.endOffset.toString()}");
Path path = Path();
path.moveTo(widget.startOffset.dx, widget.startOffset.dy);
double startX = widget.endOffset.dx / 2;
double startY = widget.startOffset.dy;
double endX = widget.endOffset.dx;
double endY = widget.endOffset.dy;
path.quadraticBezierTo(startX,startY,endX ,endY);
return path;
}
}
class PathPainter extends CustomPainter{
double fraction;
Path _path;
List<Offset> _points = List();
PathPainter(this._path,this.fraction);
Paint circleP = Paint()
..color = Colors.orange
..style = PaintingStyle.fill;
@override
void paint(Canvas canvas, Size size) {
if(_path == null) return;
print("fraction paint _____ $fraction");
PathMetrics pms = _path.computeMetrics();
PathMetric pm = pms.elementAt(0);
double pathLen = pm.length;
double circleR = 10;
Offset circleCenterOffset;
Tangent t = pm.getTangentForOffset(fraction);// 圆心
circleCenterOffset = t.position;
print("circle center ${circleCenterOffset.dx} + ${circleCenterOffset.dy}");
canvas.drawCircle(circleCenterOffset, circleR, circleP);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
}
最佳答案
class Circle extends StatefulWidget {
@override
_CircleState createState() => _CircleState();
}
class _CircleState extends State<Circle> with SingleTickerProviderStateMixin {
double _fraction = 0.0;
Animation<double> _animation;
AnimationController _controller;
@override
void initState() {
super.initState();
_controller =
AnimationController(duration: Duration(milliseconds: 300), vsync: this);
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
..addListener(() {
setState(() {
_fraction = _animation.value;
});
});
_controller.forward();
}
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: AspectRatio(
aspectRatio: 1.0,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: CustomPaint(
painter: CirclePainter(fraction: _fraction),
),
),
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
class CirclePainter extends CustomPainter {
final double fraction;
var _circlePaint;
CirclePainter({this.fraction}) {
_circlePaint = Paint()
..color = circleColor
..style = PaintingStyle.stroke
..strokeWidth = 12.0
..strokeCap = StrokeCap.round;
}
@override
void paint(Canvas canvas, Size size) {
var rect = Offset(0.0, 0.0) & size;
canvas.drawArc(rect, -pi / 2, pi * 2 * fraction, false, _circlePaint);
}
@override
bool shouldRepaint(CirclePainter oldDelegate) {
return oldDelegate.fraction != fraction;
}
}