Getmeasuredheight() и getmeasuredwidth() возвращает 0 после View.measure()

После измерения View с постоянными размерами с view.measure(), getMeasuredHeight() и getMeasureWidth() возвращает 0.

layout_view.xml, макет, который раздувается, чтобы создать представление

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="100dp"
    android:layout_height="100dp">
</FrameLayout>

которая измеряет размеры

public void measureView(Context context){
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.layout_view,null,false);

    view.measure( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

    Log.d(TAG,"Error width : " + view.getMeasuredWidth());
    Log.d(TAG,"Error heeght : " + view.getMeasuredHeight());

}

Ответ 1

Когда вы вызываете view.getMeasuredWidth() в onCreate() или onCreateView(), view еще не нарисовано. Таким образом, вам нужно добавить слушателя и получить обратный вызов при view представления. Как и в моем коде:

final ViewTreeObserver vto = view.getViewTreeObserver();
if (vto.isAlive()) {
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int viewWidth = view.getMeasuredWidth();
            // handle viewWidth here...

            if (Build.VERSION.SDK_INT < 16) {
                vto.removeGlobalOnLayoutListener(this);
            } else {
                vto.removeOnGlobalLayoutListener(this);
            }
        }
    });
}

ПРИМЕЧАНИЕ. Снимите прослушиватель для лучшей производительности!

Не вызывайте vto.removeOnGlobalLayoutListener(this) чтобы удалить слушателя. Назовите это так:

vto.getViewTreeObserver()

Ответ 2

Вы измеряете представление в onCreate(). Представление еще не нарисовано. Вы должны подождать до тех пор, пока изображение не будет нарисовано, прежде чем вы сможете его измерить.

Простое решение для этого - отправить runnable в макет. Запуск будет выполнен после того, как макет произошел.

Для получения дополнительной информации См. это сообщение

Edit попробуйте изменить

view.measure( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

к

view.measure( View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY);

Ответ 3

Попробуйте этот путь, надеюсь, что это поможет вам решить вашу проблему.

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
     int width = view.getMeasuredWidth();
     int height = view.getMeasuredHeight();

   }
});

Ответ 4

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

Ответ 5

Вы не можете использовать View.MeasureSpec.* Непосредственно в вызове measure. Вместо этого сначала makeMeasureSpec() а затем используйте его для вызова measure():

final int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT/*can be match_parent or some exact value*/, View.MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT/*can be match_parent or some exact value*/, View.MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);

Ответ 6

На всякий случай кто-то сталкивался с этой проблемой с ImageView:

Я заметил, что если ваш ImageView не имеет набора "android: src" (т.е. вы меняете его динамически), он всегда будет возвращать ноль из getMeasuredWidth/Height.

Простым обходным решением было бы установить заполнитель для представления.

Ответ 7

Вы можете использовать getViewTreeObserver в onCreate/onCreateView и других событиях.

fun setGlobalLayoutListener(view: View, method: () -> Unit) {
    val vto1 = view.viewTreeObserver
    if (vto1.isAlive) {
        vto1.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                val vto2 = view.viewTreeObserver
                if (vto2.isAlive) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        vto2.removeOnGlobalLayoutListener(this)
                    } else {
                        @Suppress("DEPRECATION")
                        vto2.removeGlobalOnLayoutListener(this)
                    }
                    // Your actions are here:
                    method()
                }
            }
        })
    }
}

И назовите его: setGlobalLayoutListener(view) {updateUI(view)}.

Я тоже пробовал

view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)

и затем вызвал view.control.measuredWidth в onCreateView()/onViewCreated(). Но в некоторых эмуляторах (API 19) он дал неверные результаты.