【问题标题】:Android custom view doesn't draw several timesAndroid自定义视图不绘制多次
【发布时间】:2015-02-23 11:02:33
【问题描述】:

我在绘制时添加了一个标志(init),它在创建视图时生成 100x500 矩形,但是当我从 onTouch 方法绘制我的 testDraw 方法时,什么都没有绘制。

绘图视图

class DrawingView extends View{
    Canvas canvas= new Canvas();;
    Paint paint= new Paint();
    boolean init;
    public DrawingView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        paint.setColor(Color.argb(255, 0, 255, 0));

        this.init = true;
    }

    public void testDraw(){
        canvas.drawRect(0,0,500,500,paint);
    }

    @Override
    public void onDraw(Canvas canvas){
        if(this.init == true){
            canvas.drawRect(0,0,500,100,paint);
            this.init = false;
        }else{
        }

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            testDraw();
        }
        return false;
    }


}

【问题讨论】:

  • 你的 testDraw() 应该只是一个invalidate()。您在 testDraw() 中用于绘制的 Canvas 与您在 onDraw 中使用的框架提供的不同
  • 您的视图正在绘制多次,或者没有绘制任何内容。并尝试检查@Balckbelt 答案

标签: android view draw


【解决方案1】:

那是因为您在不同的画布上绘图,而不是屏幕上显示的那个。

重新绘制视图的正确方法是使其无效,如下所示:

private boolean testDrawn = false;

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN) {
        testDrawn = true;
        invalidate(); // << this will make on drawn be called again
    }
    return false;
}

然后在draw方法上

   @Override
    public void onDraw(Canvas canvas){
        if(this.init == true){
            canvas.drawRect(0,0,500,100,paint);
            this.init = false;
        }else if(testDrawn){
            testDrawn = false;
            // do the drawing here ...
        }
    }

并删除这一行 Canvas canvas= new Canvas(); 视图不应该有它自己的画布。

【讨论】:

    【解决方案2】:

    来自SDK Documentation

    onTouch() - 这将返回一个布尔值来指示您的侦听器是否使用此事件。重要的是这个事件可以有多个相互跟随的动作。因此,如果在接收到 down 操作事件时返回 false,则表明您尚未消费该事件,并且对该事件的后续操作也不感兴趣。因此,事件中的任何其他操作都不会调用您,例如手指手势或最终的向上操作事件。 当 ACTION_DOWN 事件被触发时,您需要返回 true 以表明您对与同一事件相关的后续调用感兴趣。

    我认为问题在于您从 onTouch 返回 false,这意味着您对此事件以及与之相关的后续操作不感兴趣。所以我建议从这里返回 true。

    【讨论】:

      【解决方案3】:

      建议:您应该保留画布的引用,以便能够在 onDraw 发生后对其进行处理,如下所示:

      class DrawingView extends View{
          Canvas your_canvas= new Canvas(); /* change the variable name */
          Paint paint= new Paint();
          boolean init;
          public DrawingView(Context context) {
              super(context);
              // TODO Auto-generated constructor stub
              paint.setColor(Color.argb(255, 0, 255, 0));
      
              this.init = true;
          }
      
          public void testDraw(){
              your_canvas.drawRect(0,0,500,500,paint); /* changed variable name */
          }
      
          @Override
          public void onDraw(Canvas canvas){
              if(this.init == true){
                  your_canvas = canvas; /* keep canvas reference in your_canvas variable */
                  canvas.drawRect(0,0,500,100,paint);
                  this.init = false;
              }else{
              }
      
          }
      
      
          @Override
          public boolean onTouchEvent(MotionEvent event) {
              if(event.getAction() == MotionEvent.ACTION_DOWN) {
                  testDraw();
              }
              return false;
          }
      
      
      }
      

      编辑:根据@Budius 你不应该这样做......所以也许调用View.invalidate() 方法将允许你重新加载onDraw,然后做你需要的(?)

      【讨论】:

      • 不要那样做。您应该在普通视图(非表面类型)上绘制的唯一时刻是在 onDraw(或相关)回调期间。 canvas 唯一对你有效的绘制时间是在回调期间。
      • 答案已编辑:使用 invalidate 可以让您事后触发 onDraw 然后从这里做您的事情...
      【解决方案4】:

      试试这个,这是一个工作示例,如果你在画布上绘制任何东西,你应该调用一个 invalidate() 方法,以使视图重绘,而且 testDraw 方法中的画布与视图无关,你应该使用 onDraw 参数中的画布,或者为它创建一个单独的位图

      public class DrawingView extends View {
      private Bitmap cachedBitmap;
      private Canvas cachedCanvas;
      private Paint linePaint;
      
      private boolean isClicked;
      private float lastX;
      private float lastY;
      
      public DrawingView(Context context) {
          super(context);
      }
      
      public DrawingView(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
      
      public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
      }
      
      @Override
      protected void onDraw(Canvas canvas) {
          int width = getWidth();
          int height = getHeight();
          if(cachedBitmap == null && width > 0 && height > 0) {
              cachedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
              cachedCanvas = new Canvas(cachedBitmap);
              linePaint = new Paint();
              linePaint.setStyle(Paint.Style.STROKE);
              linePaint.setStrokeWidth(3);
              linePaint.setColor(Color.parseColor("#000000"));
          }
          canvas.drawBitmap(cachedBitmap, 0, 0, null);
      }
      
      @Override
      public boolean onTouchEvent(MotionEvent event) {
          switch (event.getAction()) {
              case MotionEvent.ACTION_DOWN:
                  isClicked = true;
                  break;
      
              case MotionEvent.ACTION_MOVE:
                  if(isClicked && cachedCanvas != null) {
                      cachedCanvas.drawLine(lastX, lastY, event.getX(), event.getY(), linePaint);
                      invalidate();
                  }
                  break;
      
              case MotionEvent.ACTION_UP:
                  isClicked = false;
                  break;
          }
          lastX = event.getX();
          lastY = event.getY();
          return true;
      }
      

      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多