Space (View) не работает в макете ListItem

У меня есть ListActivity с пользовательским адаптером. Этот адаптер использует следующий list_item.xml:

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

    <LinearLayout
        android:id="@+id/ll1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">

        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/default_margin"
            android:contentDescription="@string/checkbox_content_description"
            android:src="@drawable/checkbox_unchecked"
            android:background="@layout/transparent_background"
            android:focusableInTouchMode="false"
            android:adjustViewBounds="true"
            android:clickable="false"
            android:focusable="false" />

        <TextView
            android:id="@+id/tv_amount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginTop="@dimen/default_margin"
            android:focusableInTouchMode="false"
            android:clickable="false"
            android:focusable="false"
            android:textIsSelectable="false" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginTop="@dimen/default_margin">

            <TextView
                android:id="@+id/tv_product_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:ellipsize="end"
                android:focusableInTouchMode="false"
                android:clickable="false"
                android:focusable="false"
                android:textIsSelectable="false" />

        </LinearLayout>

        <TextView
            android:id="@+id/tv_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginTop="@dimen/default_margin"
            android:focusableInTouchMode="false"
            android:clickable="false"
            android:focusable="false"
            android:textIsSelectable="false" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll2"
        android:visibility="gone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_below="@id/ll1">

        <Space
            android:id="@+id/filler_space"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/default_margin"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginBottom="@dimen/default_margin"
            android:focusableInTouchMode="false"
            android:clickable="false"
            android:focusable="false" />

        <EditText
            android:id="@+id/et_amount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginBottom="@dimen/default_margin"
            android:inputType="number" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginBottom="@dimen/default_margin"
            android:padding="0dp">

            <AutoCompleteTextView
                android:id="@+id/actv_search_product"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:singleLine="true"
                android:ellipsize="end"
                android:inputType="text" />

        </LinearLayout>

        <EditText
            android:id="@+id/et_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/default_margin"
            android:layout_marginBottom="@dimen/default_margin"
            android:inputType="numberDecimal"
            android:digits="0123456789.,-" />

    </LinearLayout>

</RelativeLayout>

В метод getView адаптера я добавил следующий фрагмент кода:

// Change the width of the Filler-Space to match the Image
// and leave the height as is
Space space = (Space) view.findViewById(R.id.filler_space);
space.setLayoutParams(new LinearLayout.LayoutParams(
    imageView.getMeasuredWidth(), space.getMeasuredHeight()));

Сначала это дает следующий результат:

введите описание изображения здесь

Когда я изменяю видимость моего второго LinearLayout (ll2) на VISIBLE, это дает следующий результат:

введите описание изображения здесь

Вместо этого я хочу:

введите описание изображения здесь

Кажется, ширина Space-View вообще не изменяется. Хотя я точно знаю, что методы getView успешно вызываются благодаря сообщениям в журнале и другим вещам, которые я делаю в методе getView.

Кто-нибудь знает, что я сделал не так?

PS: когда я использую View вместо Space, я получаю тот же результат. Никогда раньше не использовал Space, поэтому я подумал, что с этим можно что-то делать.


Решение благодаря варианту Demand 4:

// Since we can't access Measured widths and heights before the View is completely loaded,
// we set up an Observer that will be called once the ListItem's layout is ready
ViewTreeObserver observer = view.getViewTreeObserver();
if(observer.isAlive()){
    // In order to access the view in the onGlobalLayout, it needs to be final, so we create a final copy here
    final View v = view;
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        // This will be called once the layout is finished, prior to displaying it
        @Override
        public void onGlobalLayout() {
            ImageView imageView = (ImageView) v.findViewById(R.id.image);
            Space space = (Space) v.findViewById(R.id.filler_space);
            // Change the width of the Filler-Space to match the Image and leave the height as is
            space.setLayoutParams(new LinearLayout.LayoutParams(imageView.getMeasuredWidth(), space.getMeasuredHeight()));
        }
    });
}

1 ответ

Решение

Вы устанавливаете ширину и высоту, если ваше пространство равно wrap_content. Это значит, что у пространства будет ширина как у его потомков, но потомков нет, а у вас ширина = 0. Дело не в пространстве, а в измерении макета в Android. Когда вы звоните свой код:

Space space = (Space) view.findViewById(R.id.filler_space);
space.setLayoutParams(new LinearLayout.LayoutParams(
    imageView.getMeasuredWidth(), space.getMeasuredHeight()));

Ваш imageView еще не измерен и возвращает ширину = 0. Он будет измерен позже перед рисованием. В getView() в адаптере вы только создаете виды, но измерения, компоновка и рисование будут позже.

У вас есть несколько способов исправить это:

  1. установите ширину вашего пространства в dp вместо wrap_content.
  2. используя относительную компоновку вместо трех линейных компоновок.
  3. Используйте TableLayout.
  4. Добавьте GlobalTreeObserver и getMeasuredWidth() в нужное время.
  5. Разместите ваш runnable в обработчике представления, чтобы получить ширину после рисования.

Я думаю, что лучший способ - это 2 и 3, потому что 4 и 5 приведут к измерению несколько раз.

Другие вопросы по тегам