更改路径偏移然后调用invalidate后,Android路径消失

时间:2015-11-09 15:57:27

标签: android android-layout animation ondraw

我设法使用自定义视图中的路径绘制楼梯和笑脸(在代码中称为Avatar)。我喜欢使用我的nextStep功能将快乐的脸移到楼梯上。 nextStep迭代当前步骤,然后调用名为moveToStep(int step)的函数,该函数将Avatar偏移到指定步骤的位置。最后,nextStep调用this.invalidate,以便再次调用onDraw,希望在新的偏移处重新绘制Avatar问题是在调用nextStep之后,即使楼梯仍然存在,Avatar也会消失。我知道它不在屏幕外,因为我检查了笑脸偏移到的坐标。

自定义视图代码

public class StaircaseView extends View {

    // setup initial color
    private final int paint_color = Color.BLACK;
    private int curr_step = 1;
    int STEPS = 5;
    private float avatar_radius;
    // defines paint and canvas
    private Paint DrawPaint;
    private int view_width, view_height, view_size;
    private Path StaircasePath, Avatar;
    private float scale, side_length;
    private char constrainer;

    public StaircaseView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupPaint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("StaircaseView", "onDraw called");
        canvas.drawPath(StaircasePath, DrawPaint);
        canvas.drawPath(Avatar, DrawPaint);
    }

    @Override
    protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
        super.onSizeChanged(xNew, yNew, xOld, yOld);

        view_height = yNew;
        view_width = xNew;
        view_size = Math.min(view_height, view_width);
        if (view_width == view_size) {
            constrainer = 'w';
        } else {
            constrainer = 'h';
        }
        scale = (float)view_size/100;

        Log.i("StaircaseView", "onSizeChanged --> view width: " + String.valueOf(xNew) + ", view height: " +  String.valueOf(yNew) + ", scale: " + String.valueOf(scale) + ", view size: " + String.valueOf(view_size));
        float padding = 5 * scale;
        StaircasePath = createStaircase(padding);
        avatar_radius = 7*scale;
        Avatar = createAvatar(0, 0, avatar_radius);
        StaircasePath.offset(0, view_height);
        moveToStep(curr_step);
    }

    public void nextStep() {
        if (curr_step < STEPS) {
            curr_step++;
        } else {
            curr_step = 1;
        }
        moveToStep(curr_step);
        this.invalidate();
    }

    private void moveToStep(int step) {
        float x = step * side_length - avatar_radius;
        float y = view_height - (step - 1) * side_length - avatar_radius;
        Log.i("StaircaseView", String.valueOf(x) + ", " + String.valueOf(y));
        Avatar.offset(x, y);
    }

    // Setup paint with color and stroke styles
    private void setupPaint() {
        DrawPaint = new Paint();
        DrawPaint.setColor(paint_color);
        DrawPaint.setAntiAlias(true);
        DrawPaint.setStrokeWidth(5);
        DrawPaint.setStyle(Paint.Style.STROKE);
        DrawPaint.setStrokeJoin(Paint.Join.ROUND);
        DrawPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    private Path createStaircase(float padding) {
        if (constrainer == 'w') {
            side_length = (view_size-padding)/(STEPS+1);
        } else {
            side_length = (view_size-padding)/STEPS;
        }
        Path path = new Path();
        float curr_x = 0;
        float curr_y = 0;

        path.moveTo(curr_x, curr_y);
        curr_x += side_length;
        path.lineTo(curr_x, curr_y);

        for(int i=0; i<STEPS; i++) {
            curr_y -= side_length;
            path.lineTo(curr_x, curr_y);
            curr_x += side_length;
            path.lineTo(curr_x, curr_y);
        }
        path.lineTo(curr_x, 0);
        path.lineTo(0, 0);

        return path;
    }

    private Path createShape(ArrayList<PointF> points) {
        Path path = new Path();
        path.moveTo(points.get(0).x, points.get(0).y);

        for(int i=1; i< points.size(); i++) {
            path.lineTo(points.get(i).x, points.get(i).y);
        }

        return path;
    }

    private Path createAvatar(int x, int y, float radius){
        Path avatar = new Path();
        float width = radius*2;

        avatar.addCircle(x, y, radius, Path.Direction.CW);
        avatar.addCircle(x - (radius /2),  y - (radius / 5), radius/5, Path.Direction.CW);
        avatar.addCircle(x + (radius / 2), y - (radius / 5), radius / 5, Path.Direction.CW);
        avatar.addRect((float) x - (radius / 5), (float) y - (radius / 5), (float) x + (radius / 5), (float) y - (radius/5), Path.Direction.CCW);

        return avatar;
    }
}

1 个答案:

答案 0 :(得分:0)

看了这个question后决定找出另一种方法来做到这一点。所以我做的是改变了我的moveToStep方法以返回坐标以移动Avatar而不是抵消他。然后我将这些坐标作为起始坐标传递给createAvatar方法。之后它起作用了。
新代码

/**
 * Created by yako on 11/5/15.
 */
public class StaircaseView extends View {

    // setup initial color
    private final int paint_color = Color.BLACK;
    private int curr_step = 1;
    int STEPS = 5;
    private float avatar_radius;
    // defines paint and canvas
    private Paint DrawPaint;
    private int view_width, view_height, view_size;
    private Path StaircasePath, Avatar;
    private float scale, side_length;
    private char constrainer;

    public StaircaseView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupPaint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("StaircaseView", "onDraw called");
        canvas.drawPath(StaircasePath, DrawPaint);
        canvas.drawPath(Avatar, DrawPaint);
    }

    @Override
    protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
        super.onSizeChanged(xNew, yNew, xOld, yOld);

        view_height = yNew;
        view_width = xNew;
        view_size = Math.min(view_height, view_width);
        if (view_width == view_size) {
            constrainer = 'w';
        } else {
            constrainer = 'h';
        }
        scale = (float)view_size/100;

        Log.i("StaircaseView", "onSizeChanged --> view width: " + String.valueOf(xNew) + ", view height: " +  String.valueOf(yNew) + ", scale: " + String.valueOf(scale) + ", view size: " + String.valueOf(view_size));
        float padding = 5 * scale;
//        Log.i("StaircaseView", String.valueOf(view_height/2 + padding/2));
        StaircasePath = createStaircase(padding);
        // Center the staircase in the view
//        if (constrainer == 'w') {
//            StaircasePath.offset(padding/2, view_height - (view_height - view_width - padding*2));
//        } else {
//            StaircasePath.offset(view_height/2 - padding/2, view_height-padding/2);
//        }
        avatar_radius = 7*scale;
        Avatar = createAvatar(moveToStep(curr_step), avatar_radius);
        StaircasePath.offset(0, view_height);
    }

    public void nextStep() {
        if (curr_step <= STEPS) {
            curr_step++;
        } else {
            curr_step = 1;
        }
        Avatar = createAvatar(moveToStep(curr_step), avatar_radius);
        this.invalidate();
    }

    private float[] moveToStep(int step) {
        float[] offset = new float[2];
        offset[0] = step * side_length - avatar_radius;
        offset[1] = view_height - (step - 1) * side_length - avatar_radius;
        Log.i("StaircaseView", "Moving avatar to "+ String.valueOf(offset[0]) + ", " + String.valueOf(offset[1]));
        return offset;
    }

    // Setup paint with color and stroke styles
    private void setupPaint() {
        DrawPaint = new Paint();
        DrawPaint.setColor(paint_color);
        DrawPaint.setAntiAlias(true);
        DrawPaint.setStrokeWidth(5);
        DrawPaint.setStyle(Paint.Style.STROKE);
        DrawPaint.setStrokeJoin(Paint.Join.ROUND);
        DrawPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    private Path createStaircase(float padding) {
        if (constrainer == 'w') {
            side_length = (view_size-padding)/(STEPS+1);
        } else {
            side_length = (view_size-padding)/(STEPS+1);
        }
        Path path = new Path();
        float curr_x = 0;
        float curr_y = 0;

        path.moveTo(curr_x, curr_y);
        curr_x += side_length;
        path.lineTo(curr_x, curr_y);

        for(int i=0; i<STEPS; i++) {
            curr_y -= side_length;
            path.lineTo(curr_x, curr_y);
            curr_x += side_length;
            path.lineTo(curr_x, curr_y);
        }
        path.lineTo(curr_x, 0);
        path.lineTo(0, 0);

        return path;
    }

    private Path createShape(ArrayList<PointF> points) {
        Path path = new Path();
        path.moveTo(points.get(0).x, points.get(0).y);

        for(int i=1; i< points.size(); i++) {
            path.lineTo(points.get(i).x, points.get(i).y);
        }

        return path;
    }

    private Path createAvatar(float[] offset, float radius){
        float x = offset[0];
        float y = offset[1];
        Path avatar = new Path();
        float width = radius*2;

        avatar.addCircle(x, y, radius, Path.Direction.CW);
        avatar.addCircle(x - (radius /2),  y - (radius / 5), radius/5, Path.Direction.CW);
        avatar.addCircle(x + (radius / 2), y - (radius / 5), radius / 5, Path.Direction.CW);
        avatar.addRect((float) x - (radius / 5), (float) y - (radius / 5), (float) x + (radius / 5), (float) y - (radius/5), Path.Direction.CCW);

        return avatar;
    }
}