Android绘制动画虚线曲线

时间:2014-04-11 11:42:18

标签: android animation bezier

我已经在这几天没有找到一个好的解决方案(至少对我而言)。

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

我有一个带有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();

        }

    }
}

2 个答案:

答案 0 :(得分:0)

假设您有要绘制的画布和要跟踪的路径,则此代码应该可以为其设置动画。

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检索段并将其添加到当前应绘制的路径所经过的时间。

答案 1 :(得分:0)

感谢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);
    }
}