Android: wrap_content is not working with ListView

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"
        ... />

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=""  />

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