Как получить размер виджета Android после раскладки?

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

<LinearLayout ... layout_height="fill_parent">
     <ImageView ... layout_height="wrap_content" />
     <TextView ... layout_height="120dp" />
</LinearLayout>

Сразу после onCreate, я хочу знать, насколько высока ImageView. Как это сделать?

Примечание: Если я вызываю getHeight() в onCreate, я получаю 0.

Я также пробовал imageView.postDelayed, он работает на эмуляторе 2.1, но не работает на эмуляторе 1.5 (я тоже получил 0).

Наконец, я попытался создать Handler, а затем я вызываю handler.postDelayed с задержкой 10 мс. Он работает как в эмуляторе 2.1, так и 1.5, но не удался, когда я запускаю программу в отладчике eclipse (Итак, я пришел к выводу, что использование задержки не гарантирует, что получение высоты произойдет после того, как изображение будет обработано.)

Ответ 1

Причина, по которой вы получаете размер 0, заключается в том, что макет не завершен до тех пор, пока операция полностью не будет создана, то есть onCreate(), onStart() и onResume() все прошли. Самый простой способ получить точный размер - вызывать ваш метод после завершения макета, например, с помощью кнопки прослушивания нажатием кнопки. Так как кнопка не отображается, пока макет не будет закончен, размер должен быть доступен к моменту запуска его прослушивателя кликов.

Это только предположение, но я думаю, что это трудно сделать именно потому, что они не хотят, чтобы люди возились с размерами макета, как только система только что закончила выкладывать экран. Если они предоставили обратный вызов onLayoutFinished(), вы могли бы застрять в цикле, если вы изменили макет в этом. Например, представьте: макет завершен; onLayoutFinished(), и вы изменяете макет там; существующий макет теперь недействителен; верстка макета; onLayoutFinished() снова вызван; ваш код снова вызван - и т.д.

Другой способ сделать это - создать пользовательский вид и переопределить метод onMeasure(int, int). Система запускает этот метод для получения размера каждого представления; если вы используете что-то вроде моего примера ниже, вы можете получить предлагаемый размер до завершения макета:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //getMeasuredHeight() and getMeasuredWidth() now contain the suggested size
}

(Я написал, что это предложенный размер, потому что я думаю, что размер файла может быть изменен после этого на основе ограничений макета. Однако это неопределенная память о чем-то, что я прочитал некоторое время назад, и я никогда не экспериментировал подробно. ) После того, как вы это сделали, вы можете использовать размер для того, что вы хотели сделать - вы даже можете изменить размер, который будет использоваться, используя setMeasuredDimension(newX, newY).

Ответ 2

Объект View предоставляет метод, называемый onSizeChanged (int w, int h, int oldw, int oldh). Он вызывается, когда макет изменяет размер одного из его компонентов. Если вы переопределите этот метод, код в вашей версии этого метода будет знать размер самого себя, как показано в следующем фрагменте.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    bounds = new Rect();
    this.getDrawingRect(bounds);
    // bounds will now contain none zero values
}