Подтвердить что ты не робот

Когда вызывается View.onMeasure()?

Когда

View.onMeasure(int widthMeasureSpec, int heightMeasureSpec)

называется? У меня есть Activity, который должен выполнить действие после onMeasure.

Мой вопрос такой же, как ответ на оставшийся без ответа вопрос. Документация View гласит, что onMeasure вызывается, когда вызывается requestLayout(), который, по-видимому, вызывается представлением сам по себе, когда он полагает, что он больше не может соответствовать его текущему границы.

Однако это не говорит мне, когда моя деятельность может предположить, что мой View был измерен. Я использовал этот код для расширения ImageView для создания TouchImageView. Здесь было предложено, чтобы я использовал метод onMeasure для масштабирования моего образ. Я хочу обновить значение TextView после ImageView, чтобы отобразить процент, на который масштабируется изображение.

4b9b3361

Ответ 1

onMeasure вызывается, когда родительский вид должен вычислять макет. Как правило, onMeasure можно вызывать несколько раз в зависимости от разных присутствующих детей и их параметров компоновки.

Лучший способ сделать что-то, когда onMeasure называется (я думаю), чтобы создать свой собственный элемент управления, расширить ImageView и переопределить onMeasure (просто вызовите super.onMeasure и сделайте все, что вы хотели бы сделать).

Если вы это сделаете, просто имейте в виду, что на Measure можно вызывать несколько раз с разными параметрами, поэтому все, что измеряется, может быть не окончательной шириной и высотой того, что будет отображаться на самом деле.

Ответ 2

Вы можете получить свои пользовательские измерения в onSizeChanged.

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

    // use the provided width and height for whatever you need
}

Объяснение

Когда создается представление, это порядок, в котором вызываются следующие методы:

  • Конструктор
  • onFinishInflate (предполагая, что вы использовали конструктор xml)
  • onAttachedToWindow
  • onMeasure
  • onSizeChanged
  • onLayout
  • onDraw

Самое раннее, что вы можете получить измерения вида, находится в onMeasure. Перед этим ширина и высота 0. Однако единственное, что вы должны делать в onMeasure, - это определить размер представления. Этот метод вызывается несколько раз, в то время как представление сообщает родителям, насколько большой он хочет быть, но родитель определяет фактический конечный размер. (См. этот ответ о том, как использовать onMeasure.)

Если вы хотите использовать измеренный размер для чего-либо, самое раннее место для этого - onSizeChanged. Он вызывается всякий раз, когда создается представление, потому что размер изменяется с 0 на любой размер.

Вы также можете использовать onLayout, хотя, насколько я понимаю, onLayout предназначен для настройки того, как выкладываются любые дочерние элементы вашего пользовательского представления. Его также можно вызвать чаще, чем onSizeChanged, например, если вы вызываете requestLayout(), когда размер фактически не изменился.

Вы также можете получить доступ к размеру в onDraw с помощью getMeasuredWidth() и getMeasuredHeight(). Однако, если вы используете их для проведения тяжелых вычислений, лучше сделать это заранее. Вообще говоря, старайтесь как можно больше сохранить onDraw, так как это можно назвать несколько раз. (Он вызывается при каждом вызове invalidate().)

Смотрите сами

Если вы мне не верите, вы можете увидеть порядок событий, как они вызывают в пользовательском представлении ниже. Вот результат:

constructor called, measured size: (0, 0)
onFinishInflate called, measured size: (0, 0)
onAttachedToWindow called, measured size: (0, 0)
onMeasure called, measured size: (350, 1859)
onMeasure called, measured size: (350, 350)
onMeasure called, measured size: (350, 2112)
onMeasure called, measured size: (350, 350)
onSizeChanged called, measured size: (350, 350)
onLayout called, measured size: (350, 350)
onDraw called, measured size: (350, 350)

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.viewlifecycle.CustomView
        android:id="@+id/customView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@color/colorAccent"/>

</RelativeLayout>

CustomView.java

public class CustomView extends View {

    private void printLogInfo(String methodName) {
        Log.i("TAG", methodName + " called, measured size: (" + getMeasuredWidth() + ", " + getMeasuredHeight() + ")");
    }

    // constructors

    public CustomView(Context context) {
        super(context);
        printLogInfo("Programmatic constructor");
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        printLogInfo("XML constructor");
    }

    // lifecycle methods

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        printLogInfo("onFinishInflate");
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        printLogInfo("onAttachedToWindow");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        printLogInfo("onMeasure");
    }

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

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        printLogInfo("onLayout");
    }

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

Дальнейшее чтение