Android: wrap_content is not working with ListView
Asked Answered
H

5

35

I am working on android. I want my list view to wrap its content horizontally and not to fill all the width. The wrap_content properties is not working. What to do?

Hema answered 2/7, 2012 at 13:51 Comment(0)
H
39

As Romain Guy (Google Engineer works on UI toolkit) Said in his post

By setting the width to wrap_contentyou are telling ListView to be as wide as the widest of its children. ListView must therefore measure its items and to get the items it has to call getView() on the Adapter. This may happen several times depending on the number of layout passes, the behavior of the parent layout, etc.

So if you set the layout width or layout height of your ListView to wrap_content the ListView will try to measure every single view that is attached to it - which is definitely not what you want.

Keep in mind: avoid setting wrap_content for ListViews or GridViews at all times, for more details see this Google I/O video talking about the world of listview

Hartsfield answered 2/7, 2012 at 14:3 Comment(4)
This advice doesn't exactly seem universal. The ListView/Adapater combination is more generic and scalable than people might realize at first, which means that people also might not realize the consequences of using wrap_content with arbitrary datasets. But that's not to say that there aren't plenty of cases where the dataset is of a fixed or limited size. In those cases, using wrap_content would be more of a judgement call.Skipp
This seems like something lint should warn about - but it currently doesn't.Eveevection
I don't know why this answer was accepted: it doesn't answer the question at all. It also parrots back the Romain's Guy post - which was about a completely different question: the number of times a layout is measured - and points to a video that actually explain why wrap_content should work, at least for 3 list items, and "sort of work" for more complex lists (at a considerable performance cost).Cottbus
until now, the lint does not do this. could have saved me from hours of trying!Prosy
S
65

In order achieve wrap_content height in ListView, we need to use CustomListView that extends our native ListView.

MyListView.java

public class MyListView extends ListView {

    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyListView(Context context) {
        super(context);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }

}

in your layout use custom view like this,

layout.xml

<com.yourpackagename.MyListView
        ...       
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ... />
Studio answered 28/7, 2015 at 11:22 Comment(6)
Fantastic! Worked for me when I wanted to use a ListView inside a RecyclerView.Innutrition
This answer is useful, but when ListView is inside a RecyclerView, scrolling up appears to be buggy. So the real solution is to override onMeasure method. See this answer: https://mcmap.net/q/411791/-listview-same-height-as-contentSouthwick
Doesn't work if, for example, the second row is bigger than the first.Waaf
Height is working good, what about width, width taking full length, If I taking wrapcontnet as width not workingTranscendental
Worked like a charmLiberia
Doesn't work for me. In my case, the parent layout is RelativeLayout and layout_height="wrap_content".Slighting
H
39

As Romain Guy (Google Engineer works on UI toolkit) Said in his post

By setting the width to wrap_contentyou are telling ListView to be as wide as the widest of its children. ListView must therefore measure its items and to get the items it has to call getView() on the Adapter. This may happen several times depending on the number of layout passes, the behavior of the parent layout, etc.

So if you set the layout width or layout height of your ListView to wrap_content the ListView will try to measure every single view that is attached to it - which is definitely not what you want.

Keep in mind: avoid setting wrap_content for ListViews or GridViews at all times, for more details see this Google I/O video talking about the world of listview

Hartsfield answered 2/7, 2012 at 14:3 Comment(4)
This advice doesn't exactly seem universal. The ListView/Adapater combination is more generic and scalable than people might realize at first, which means that people also might not realize the consequences of using wrap_content with arbitrary datasets. But that's not to say that there aren't plenty of cases where the dataset is of a fixed or limited size. In those cases, using wrap_content would be more of a judgement call.Skipp
This seems like something lint should warn about - but it currently doesn't.Eveevection
I don't know why this answer was accepted: it doesn't answer the question at all. It also parrots back the Romain's Guy post - which was about a completely different question: the number of times a layout is measured - and points to a video that actually explain why wrap_content should work, at least for 3 list items, and "sort of work" for more complex lists (at a considerable performance cost).Cottbus
until now, the lint does not do this. could have saved me from hours of trying!Prosy
M
4

It can be implemented by using LinearLayout.

Create like this example:

public class LinearLayoutAdapter   {
    LinearLayout linearLayout;
    ArrayList<String>  arrayList 
    private View rootView;
    private static LayoutInflater inflater;

    public ChoicesAdapter_(ArrayList<String>  arrayList ,LinearLayout linearLayout)
    {
        this.index =index;
        this.arrayList=arrayList;
        this.linearLayout=linearLayout;
        notifyDataSetChanged();
    }
    private void notifyDataSetChanged() {
        linearLayout.removeAllViews();
        for (int i =0;i<getCount();i++){
            linearLayout.addView(getView(i,null,null));
        }
    }
    public int getCount() {
        return  arrayList.size();
    }
    public Object getItem(int position) {
        return null;
    }
    public long getItemId(int position) {
        return 0;
    }
    public View getView(final int position, View convertView, ViewGroup parent) {
       rootView = inflater.inflate(R.layout.row_list, null);
       TextView  textView = (TextView)rootView.findViewById(R.id.text);    
       textView.setText(arrayList.get(position));
        return rootView;
    }
}

MainActivity example:

public class MainActivity extends Activity    {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayList<String>  arrayList = new  ArrayList<String>();
        arrayList.add("Accent");
        arrayList.add("Acclaim");
        arrayList.add("Accord");
        arrayList.add("Achieva");
        arrayList.add("Aerio");
        arrayList.add("Aerostar");
        LinearLayout linearLayout = (LinearLayout)findViewById(R.id.linearLayout);
        linearLayoutAdapter= LinearLayoutAdapter(arrayList,linearLayout);
    }
}

XML example:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:textColor="@color/dark_gray"
    android:background="@color/white"
    android:textSize="20dp"
    android:text=""  />
Mckay answered 10/7, 2016 at 18:5 Comment(1)
Yes, you can do this, but you loose (or have a lot to implement) the recycle system for listitem views. It works fine for few items but, with few items you may consider not using a listview neither an adapter.Conformance
C
3
I want my list view to wrap its content horizontally and not to fill all the width. 

In case of List View you can't give wrap_content , because if you give wrap_content for List View only first three items(rows) will be shown rest will be ignored.. So don't use wrap_content.. Always use fill_parent or match_parent for List View

For efficient design on List View you can see this World of ListView

Crayton answered 2/7, 2012 at 14:3 Comment(1)
Don't use fill_parent. It was deprecated in Android 2.2: developer.android.com/reference/android/view/…Skipp
I
0

I know I am little too late for answering this question. But in my opinion, if you want your ListView to have somewhat of a wrap_content behavior, you can set its start and end margins to be some static value. This worked in my case. If you are concerned about doing it for various screen sizes, there is a really helpful library to handle this scenario. Scalable DP. Do check it once in github.

Incurrence answered 6/1, 2022 at 19:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.