Когда вызывается View.onMeasure ()? - PullRequest
23 голосов
/ 09 июля 2011

Когда

View.onMeasure(int widthMeasureSpec, int heightMeasureSpec)

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

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

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

Ответы [ 2 ]

16 голосов
/ 15 февраля 2017

Вы можете получить измерения своего пользовательского представления в 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
}

Пояснение

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

  1. Конструктор
    • CustomView(Context context) (если создан программно)
    • CustomView(Context context, AttributeSet attrs) (если создан из XML)
  2. onFinishInflate (при условии, что вы использовали конструктор xml)
  3. onAttachedToWindow
  4. onMeasure
  5. onSizeChanged
  6. onLayout
  7. onDraw

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

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

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

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

Убедитесь сами

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

XML 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");
    }
}

Дополнительная информация

14 голосов
/ 09 июля 2011

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

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

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

...