Как я могу получить размер холста пользовательского представления вне метода onDraw?

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

Идеальное решение позволило бы мне выполнять эти вычисления в методе onSizeChanged, поэтому мне интересно... можно ли каким-либо образом получить объект Canvas (или, по крайней мере, его размеры) вне метода onDraw?

Мой код ниже. Он рисует радиус окружности под заданным углом. Когда я использую canvas.centerX() для определения начальной и конечной точек радиуса, все работает отлично. Если я использую параметры, переданные в onSizeChanged, они даже близко не будут правильными.

@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);
}

person dfetter88    schedule 11.07.2011    source источник


Ответы (1)


Для рисования не следует использовать размеры объекта 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);
    }

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

person Che Jami    schedule 11.07.2011
comment
Меня бы это устроило, но метод onSizeChanged не дает мне правильных чисел. Например, предположим, что я хочу нарисовать текст в центре представления. Если я сохраняю значения, переданные в onSizeChanged, и использую их, чтобы определить, где должен быть отрисован текст, он не отрисовывается в правильном месте. Если я использую размеры холста, чтобы определить, где должен быть нарисован текст, он работает отлично. - person dfetter88; 11.07.2011
comment
Если вы сравните свои значения w/2 и h/2 с результатами методов canvas.centerX() и canvas.centerY(), вы увидите, что значения разные. - person dfetter88; 11.07.2011
comment
Когда я использую ваш код, текст вообще не появляется, потому что w/2 и h/2 дают координаты, которые больше, чем холст. Таким образом, текст рисуется в месте, не отображаемом на экране. - person dfetter88; 11.07.2011
comment
Ширина и высота холста дадут вам ширину и высоту экрана. Разве вы не хотите использовать размеры вашего представления (указанные в onSizeChanged)? Было бы неплохо, если бы вы могли показать еще немного своего кода рисования, чтобы помочь нам точно определить проблему. - person Che Jami; 11.07.2011
comment
Я обновил OP еще немного кода. Я хотел бы иметь возможность использовать размеры представления, но у меня это не работает. - person dfetter88; 11.07.2011
comment
Дайте мне знать, если обновленный код дает желаемое поведение. Вы делаете часы или что-то в этом роде? :П - person Che Jami; 12.07.2011
comment
Он работает только тогда, когда в родительской группе просмотра (FrameLayout в данном случае) не было определено отступов. К сожалению, этого недостаточно для моего текущего проекта. Что бы я ни пытался, я не могу заставить его работать должным образом, если я не использую границы клипа холста. - person dfetter88; 12.07.2011
comment
Я поместил CustomView в дополненный FrameLayout, и, похоже, он работает нормально. Мы можем что-то упустить здесь... - person Che Jami; 12.07.2011
comment
Спасибо за вашу помощь! Вы повели меня по правильному пути. Проблема заключалась в том, как я устанавливал размеры в своем методе onMeasure. У меня был предпочтительный размер 300dip, но когда был выбран этот размер, начались проблемы. Мое решение состояло в том, чтобы создать новые MeasureSpec с выбранным размером и передать их методу super.onMeasure. Еще раз спасибо... Если бы не ваша помощь, я бы уже давно отказался от этого. Теперь ваш метод работает отлично! - person dfetter88; 12.07.2011