Как получить размер виджета 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 (Итак, я делаю вывод, что использование задержки не гарантирует, что получение высоты произойдет после макетирования изображения.)


person Randy Sugianto 'Yuku'    schedule 19.05.2010    source источник


Ответы (2)


Причина, по которой вы получаете размер 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).

person Steve Haley    schedule 19.05.2010
comment
Большое спасибо. Звучит так. Я попробую это. - person Randy Sugianto 'Yuku'; 20.05.2010
comment
Это большое ограничение ИМХО. Невозможно получить показатели без переопределения представления или макета или добавления кнопки, которая вам на самом деле не нужна. - person Sébastien; 29.01.2012

Объект 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
}
person securelpb    schedule 01.01.2011