How can I get the canvas size of a custom view outside of the onDraw method?

Refresh

November 2018

Views

28.4k time

26

I need to be able to access the size of the view's canvas to perform some calculations. For some reason, the size of the view passed to onSizeChanged is different than the size of the canvas passed to onDraw. My current workaround uses a boolean flag to determine when I need to do the calculations.

The ideal solution would allow me to do these calculations in the onSizeChanged method, so I'm wondering... is there any way I can get ahold of the Canvas object (or at least it's dimensions) outside of the onDraw method?

My code is below. It is draws the radius of a circle at a given angle. When I use canvas.centerX() to determine the start points and end points for the radius, everything works perfectly. If I use the parameters passed into onSizeChanged, it isn't even remotely close to correct.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  mSizeChanged = true;
}

@Override
protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);

  if (mSizeChanged) {
    RectF bounds = new RectF(canvas.getClipBounds());
    float centerX = bounds.centerX();
    float centerY = bounds.centerY();
    float radianAngle = (float) Math.toRadians(mStartAngle);

    mRadius[0] = center;
    mRadius[1] = center;
    mRadius[2] = center + center * FloatMath.cos(radianAngle);
    mRadius[3] = center + center * FloatMath.sin(radianAngle);
    mSizeChanged = false;
  }

  mPaint.setColor(0xFF330000);
  mPaint.setStrokeWidth(1);
  canvas.drawLines(mRadius, mPaint);
}

1 answers

32

Для рисования целей, вы не должны реально использовать размеры Canvasобъекта.

Просто используйте размеры , предоставленные Вам в onSizeChangedметоде. Вы можете либо сохранить размеры для использования в onDrawспособе или изменить размер / притягивать к отступающей растровое изображение, которое вы можете рисовать позже.

Обновить:

Быстро взбитый код, это выглядит, как это работает:

public class CustomView extends View{
    private Paint paint;
    private int w;
    private int h;

    public CustomView(Context context, AttributeSet attr) {
        super(context, attr);
        paint = new Paint();
        paint.setTextAlign(Align.CENTER);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        this.w = w;
        this.h = h;
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        canvas.drawText("TEST", w/2, h/2, paint);   
    }
}

Обновление 2

После обновления кода круга.

Мы можем это сделать:

   @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        float centerX = (float) w/2;
        float centerY = (float) h/2;
        float radianAngle = (float) Math.toRadians(startAngle);

        radius[0] = centerX;
        radius[1] = centerY;
        radius[2] = centerX + centerX * FloatMath.cos(radianAngle);
        radius[3] = centerY + centerY * FloatMath.sin(radianAngle);

        paint.setColor(0xFF330000);
        paint.setStrokeWidth(1);
        canvas.drawLines(radius, paint);
    }

Вы увидите, что это теперь работает на любом размере зрения.