Android绘制动画虚线曲线



我已经研究了好几天,没有找到一个好的解决方案(至少对我来说)。

基本上,我需要做的是绘制一条动画虚线,这将代表基本游戏的导弹轨迹。该轨迹将接受起始、中间和最终的x,y。我刚开始读了很多关于动画曲线甚至直线的问答,但与我必须做的相比,它们看起来真的很复杂。

我有一个带有onclick监听器的按钮,它可以触发导弹发射,但到目前为止,它只是画静态线,没有任何动画。

你还记得这个吗?这就是我想要实现的目标:http://www.youtube.com/watch?v=UDc3ZEKl-Wc

香蕉的轨迹没有画出来,但是,你有这个想法。


再次,从你的例子开始,我试图使用数组和for循环同时绘制曲线,但我得到的是,有时(并非总是)应用程序会因nullpointer异常而崩溃,不知道为什么。我做错了什么?这是我的代码:

public class DrawDottedCurve extends View {
    Path[] path = new Path[8];
    Path[] drawingPath = new Path[8];
    PathMeasure[] measure = new PathMeasure[8];
    Path[] segmentPath = new Path[8];
    float[] length = new float[8];
    float[] start = new float[8];
    float[] percent = new float[8];
    Paint paint = new Paint();
    float x1;
    float y1;
    float x3;
    float y3;
    long k = 0;
    Canvas canvas;
    Random r = new Random();
    public DrawDottedCurve(Context context, int a, int b, int c, int d) {
        super(context);
        x1 = a;
        y1 = b;
        x3 = c;
        y3 = d;
        paint.setAlpha(255);
        paint.setStrokeWidth(2);
        paint.setColor(Color.RED);
        paint.setStyle(Style.STROKE);
        paint.setPathEffect(new DashPathEffect(new float[] { 2, 4 }, 50));
        for (int i = 0; i < 8; i++) {
            k = r.nextInt(100 - 30) + 30;
            path[i] = new Path();
            path[i].moveTo(x1 + k, y1 + k); //
            path[i].quadTo((x3 + k - x1 + k) / 2, (y3 + k - y1 + k) / 2,
                    x3 + k, y3 + k); // Calculate Bezier Curves
        }
        final long DRAW_TIME = 10000;
        CountDownTimer timer = new CountDownTimer(DRAW_TIME, 100) {
            @Override
            public void onTick(long millisUntilFinished) {
                Log.d("Timer", "Inizio");
                for (int i = 0; i < 8; i++) {
                    start[i] = 0;
                    measure[i] = new PathMeasure();
                    measure[i].setPath(path[i], false);
                    percent[i] = ((float) (DRAW_TIME - millisUntilFinished))
                            / (float) DRAW_TIME;
                    segmentPath[i] = new Path();
                    drawingPath[i] = new Path();
                    length[i] = measure[i].getLength() * percent[i];
                    measure[i].getSegment(start[i], length[i], segmentPath[i],
                            true);
                    start[i] = length[i];
                    drawingPath[i].addPath(segmentPath[i]);

                }
                invalidate();
;
            }
            @Override
            public void onFinish() {
                for (int i = 0; i < 8; i++) {
                    measure[i].getSegment(start[i], measure[i].getLength(),
                            segmentPath[i], true);
                    drawingPath[i].addPath(segmentPath[i]);

                }
                invalidate();   
                Log.d("Timer", "Fine");
            }
        };
        timer.start();
    }
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < 8; i++) {
            canvas.drawPath(drawingPath[i], paint);
            invalidate();
        }
    }
}

假设你有一个画布可以绘制,并且你想跟踪这个代码的路径应该可以为它制作动画。

private void init() {
    missilePath = new Path();
    missileDrawPath = new Path();
    mPaint = new Paint();
    mPaint.setStrokeWidth(3);
    mPaint.setColor(Color.BLACK);
    mPaint.setStyle(Style.STROKE);
    mPaint.setAntiAlias(true);
    PathEffect dashEffect = new DashPathEffect(new float[] {2, 4}, 0);
    mPaint.setPathEffect(dashEffect);
    final long DRAW_TIME = 5000;
    timer = new CountDownTimer(DRAW_TIME, 100) {
        PathMeasure measure = new PathMeasure();
        Path segmentPath = new Path();
        float start = 0;
        @Override
        public void onTick(long millisUntilFinished) {
            measure.setPath(missilePath, false);
            float percent = ((float) (DRAW_TIME - millisUntilFinished)) / (float) DRAW_TIME;
            float length = measure.getLength() * percent;
            measure.getSegment(start, length, segmentPath, true);
            start = length;
            missileDrawPath.addPath(segmentPath);
            invalidate();
        }
        @Override
        public void onFinish() {
            measure.getSegment(start, measure.getLength(), segmentPath, true);
            missileDrawPath.addPath(segmentPath);
            invalidate();
        }
    };
    timer.start();
}

@Override
public void onDraw(Canvas c) {
    super.onDraw(c);
    c.drawPath(missileDrawPath, mPaint);
}

基本上,计时器启动,根据经过的时间,从missilePath检索一个段,并将其添加到当前应绘制的路径中。

感谢SceLus工作得非常好,以下是针对最终遇到相同问题的人的完整代码。

类构造函数将Bezier曲线的起始点和最终点x和y作为输入,简单地计算中间控制点,然后根据SceLus代码绘制所有内容。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.os.CountDownTimer;
import android.view.View;
public class DrawDottedCurve extends View {
    Path path = new Path();
    Path drawingPath = new Path();
    Paint paint = new Paint();
    float x1;
    float y1;
    float x3;
    float y3;
    public DrawDottedCurve(Context context, int a, int b, int c, int d) {
        super(context);
        x1 = a;
        y1 = b;
        x3 = c;
        y3 = d;
        paint.setAlpha(255);
        paint.setStrokeWidth(2);
        paint.setColor(Color.RED);
        paint.setStyle(Style.STROKE);
        paint.setPathEffect(new DashPathEffect(new float[] { 2, 4 }, 50));
        path.moveTo(x1, y1); //
        path.quadTo((x3 - x1) / 2, (y3 - y1) / 2, x3, y3); // Calculate Bezier Curve
        final long DRAW_TIME = 10000;
        CountDownTimer timer = new CountDownTimer(DRAW_TIME, 100) {
            PathMeasure measure = new PathMeasure();
            Path segmentPath = new Path();
            float start = 0;
            @Override
            public void onTick(long millisUntilFinished) {
                measure.setPath(path, false);
                float percent = ((float) (DRAW_TIME - millisUntilFinished))
                        / (float) DRAW_TIME;
                float length = measure.getLength() * percent;
                measure.getSegment(start, length, segmentPath, true);
                start = length;
                drawingPath.addPath(segmentPath);
                invalidate();
            }
            @Override
            public void onFinish() {
                measure.getSegment(start, measure.getLength(), segmentPath,
                        true);
                drawingPath.addPath(segmentPath);
                invalidate();
            }
        };
        timer.start();
    }
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(drawingPath, paint);
    }
}

最新更新