android - 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;
}
}
}
}
该程序完美运行。我尽可能地深入研究它。但是在它之后和观看文档之后,我无法理解两件事:
- 第一次调用 onDraw(Canvas canvas) 方法的位置和时间。
- 为什么 onDraw 的末尾有 invalidate()?
我的意思是文档说:
使整个视图无效。如果视图可见,onDraw(android.graphics.Canvas) 将在未来的某个时间点被调用。
所以……如果这个方法是用来调用onDraw的,为什么不直接调用呢?有什么不同?
解决方案
1) 当视图无效时,框架将调用 onDraw 方法。视图在首次出现在屏幕上时是无效的,因此当您为活动设置内容视图时,它们的布局和其中的所有视图都将被测量、布局,然后绘制(通过 onDraw)。
之后,如果需要,UI 线程将每 16 毫秒左右调用一次 onDraw(因此它以 60 FPS 的速度绘制)。
2) 它将视图标记为需要重绘,因此下次绘制屏幕时会调用 onDraw。否则它会被跳过,因为我们可以假设它是不需要的。
为什么不直接调用 onDraw - 效率。在一个非常简单的绘图系统中,你会 - 但绘图很耗时,你不想做的比你必须做的更多。因此,不是立即绘制(无论如何都不会工作,您没有正确的 Canvas 可以传递给 onDraw),而是调用 invalidate 并且系统将在需要时定期调用 onDraw。
请注意,这不是特别好的代码。特别是,让 onDraw 触发更新球位置而不是使用计时器的移动是 icky。结果导致 onDraw 调用无效也有点恶心。更好的解决方案是将视图、模型和计时器分离到更多的 MVC 或 MVP 系统中。
推荐阅读
- kotlin - 如何迭代字符列表并比较不同的元素
- asp.net - Json.NET 反序列化选择列表/多选列表
- mysql - IntelliJ 中列名旁边的图标是什么意思?
- c# - 仅使用 MSBuild BuildManager 构建单个项目
- javascript - 在循环中更改组件状态
- arrays - 在 go 中创建异构 json 数组
- amazon-web-services - 什么是 AWS Auto Scaling?它对大型项目有什么帮助?
- selenium - 我正在尝试处理自动化框架,但出现空指针异常
- docker - docker-compose.yml 版本 3 中的 mem_limit
- sql-server - SQL ServiceBroker 错误“在 sys.transmission_queue 中找到与同一对等方的先前存在的连接”?