onDraw和invalidate方法

时间:2018-12-11 21:47:56

标签: android

我正在做一个学校项目。在这个项目中,我必须执行一个程序,该程序在屏幕上有一个或多个弹跳球。我在Google上做了一些研究,以帮助我解决这个问题,然后找到了以下代码:

public class BouncingBallInside extends View {
private List<Ball> balls = new ArrayList<>();

public BouncingBallInside(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}
public BouncingBallInside(Context context) {
    super(context);
    init();
}
private void init(){
    //Add a new ball to the view
    balls.add(new Ball(50,50,100, Color.RED));
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //Draw the balls
    for(Ball ball : balls){
        //Move first
        ball.move(canvas);
        //Draw them
        canvas.drawOval(ball.oval,ball.paint);
    }
    invalidate(); // See note
} 
}

球类:

public class Ball{

public int x,y,size;
public int velX = 10;
public int velY=7;
public Paint paint;
public RectF oval;

public Ball(int x, int y, int size, int color){
    this.x = x;
    this.y = y;
    this.size = size;
    this.paint = new Paint();
    this.paint.setColor(color);
}

public void move(Canvas canvas) {
    this.x += velX;
    this.y += velY;
    this.oval = new RectF(x-size/2,y-size/2,x+size/2,y+size/2);

    //Do we need to bounce next time?
    Rect bounds = new Rect();
    this.oval.roundOut(bounds); ///store our int bounds

    //This is what you're looking for ▼
    if(!canvas.getClipBounds().contains(bounds)){
        if(this.x-size<0 || this.x+size > canvas.getWidth()){
           velX=-velX;
        }
        if(this.y-size<0 || this.y+size > canvas.getHeight()){
            velY=-velY;
        }
    }
}
}

该程序正常运行。 我尽可能地深入研究了它。但是之后,在看完文档之后,我无法理解两件事:

  1. 第一次调用onDraw(Canvas canvas)方法的位置和时间。
  2. 为什么在onDraw的末尾有invalidate()?

我的意思是文档说:

  

使整个视图无效。如果该视图可见,则将来会在某个时候调用onDraw(android.graphics.Canvas)。

所以...如果此方法用于调用onDraw,为什么不直接调用它呢?有什么区别?

1 个答案:

答案 0 :(得分:0)

1)只要视图无效,框架就会调用onDraw方法。视图在首次出现在屏幕上时是无效的,因此,当您为活动设置内容视图时,将对其进行布局,并且将对其进行测量,布局和绘制(通过onDraw)。

此后,如果需要,UI线程将每隔16ms左右调用一次onDraw(因此它以60 FPS的速度绘制)。

2)将需要重新绘制的视图标记为视图,因此下次调用屏幕时将调用onDraw。否则,它将被跳过,因为我们认为它是不需要的。

为什么不直接调用onDraw效率。在一个非常简单的绘图系统中,您会-但绘图很费时,您不想做的事比您必须做的要多。因此,您可以立即调用而不是立即绘制(无论如何都无法正常工作,您将没有合适的Canvas可以传递给onDraw),而是调用invalidate,并且如果需要,系统会定期调用onDraw。

请注意,这并不是特别好的代码。尤其是,让onDraw触发移动来更新球的位置而不是使用计时器的做法令人讨厌。结果使onDraw调用无效也很麻烦。更好的解决方案是将视图,模型和计时器分离为更多的MVC或MVP系统。