自定义View上的invalidate()不会导致调用onDraw(Canvas c)

时间:2011-10-26 16:42:44

标签: android view

对于我的活动,我使用3个自定义视图堆叠。 较低的一个是SurfaceView全屏,中间的一个是从GridView派生的,并覆盖onDraw以添加自定义图形。

顶部的一个直接来自View,位于屏幕的一角,充当一个旋钮来控制其他两个视图(这是有问题的视图)。

为此视图添加自定义动画,我使用了这种模式:

public class StubKnobView extends View{

    private Drawable knob;
    private Point knobPos;
    private float rotation;
    private boolean needsToMove;

    public void moveKnob(){
            /* ...various calculations... */
            this.needsToMove=true;
            invalidate();   //to notify the intention to start animation
    }

    private void updateAnimation(){
        /* ........... */
        this.needsToMove= !animationComplete;
        invalidate();        
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int saveCount=canvas.getSaveCount();
        canvas.save();
        canvas.rotate(this.rotation, this.knobPos.x, this.knobPos.y );
        this.knob.draw(canvas);
        canvas.restoreToCount(saveCount);
        if(this.needsToMove){
            updateAnimation();
        }
    }
}

理想情况下,如果有动画待定,则在每个绘制周期后视图应自动失效。

现在这不起作用,强制动画我必须触摸屏幕才能导致onDraw循环。 使用开发工具的“显示屏幕更新”,我看到没有屏幕无效/更新周期发生,除了我点击屏幕。 指定脏矩形也没有效果。

那么,任何想知道为什么这个无效/绘制周期不起作用的想法是什么意思?

2 个答案:

答案 0 :(得分:2)

我很喜欢这种情况,并且怀疑invalidate()没有再次调用onDraw()

在简化了业务代码之后,结果发现存在一个死循环 - 过多的迭代会阻塞UI线程。

所以,我的建议是确保UI线程首先顺利进行。

答案 1 :(得分:0)

在View中使用私有类尝试类似的操作。我们的想法是不要在invalidate()内拨打onDraw()。相反,将其发布在正在运行的队列中。在View构造函数中实例化私有类,然后在需要动画时调用animateKnob.start()onDraw()可以专注于绘图。

public void moveKnob(){

  // update the state to draw... KnobPos, rotation
  invalidate()

}


private class AnimateKnob{
   public void start(){
      // Do some calculations if necessary 
      // Start the animation
      MyView.this.post( new Runnable() {
        stepAnimation()
      });
   }

   public void stepAnimation(){
     // update the animation, maybe use an interpolator.
     // Here you could also determine if the animation is complete or not

     MyView.this.moveKnob();

     if( !animationComplete ){
       // Call it again
       MyView.this.post( new Runnable() {
          stepAnimation()
       });
     }

   } 

}