首页 > 解决方案 > onDraw 和无效方法

问题描述

我正在做一个学校项目。在这个项目中,我必须做一个程序,让一个或多个球在屏幕上弹跳。我在谷歌上做了一些研究来帮助我,我发现了这段代码:

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的,为什么不直接调用呢?有什么不同?

标签: android

解决方案


1) 当视图无效时,框架将调用 onDraw 方法。视图在首次出现在屏幕上时是无效的,因此当您为活动设置内容视图时,它们的布局和其中的所有视图都将被测量、布局,然后绘制(通过 onDraw)。

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

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

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

请注意,这不是特别好的代码。特别是,让 onDraw 触发更新球位置而不是使用计时器的移动是 icky。结果导致 onDraw 调用无效也有点恶心。更好的解决方案是将视图、模型和计时器分离到更多的 MVC 或 MVP 系统中。


推荐阅读