AnZyuZya
AnZyuZya

Reputation: 201

Get height of ListView with custom adapter

I have listView within scrollView (yes, I know thats bad approach. Better to use headers/footers). I know that scrollView and listView have both scroll and that causes some conflict. In this case I need to set height of list manually. And thats the problem since listView has custom adapter.

Layout:

<?xml version="1.0" encoding="utf-8"?>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ScrollView01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none" >
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/fragment_lessons"
        android:background="#FAF9F9"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.cbsystematic.mobile.itvdn.LessonsFragment">

        <TextView
            android:id="@+id/course_title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Описание курса: "
            android:textSize="16sp"
            android:textStyle="bold"
            android:textColor="#000000"/>

        <TextView
            android:id="@+id/course_description"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:layout_below="@id/course_title"
            android:textColor="#000000"/>

        <TextView
            android:id="@+id/course_duration"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textStyle="italic"
            android:layout_below="@id/course_description"
            android:textColor="#000000"/>

        <ListView android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/course_duration"/>
        </RelativeLayout>
    </LinearLayout>
</ScrollView>

Custom List adapter:

class LessonsItemAdapter extends ArrayAdapter<LessonData> {
private Activity myContext;
private ArrayList<LessonData> datas;

public LessonsItemAdapter(Context context, int textViewResourceId, ArrayList<LessonData> objects){
    super(context, textViewResourceId, objects);

    myContext = (Activity) context;
    datas = objects;
}

public View getView(int position, View convertView, ViewGroup parent){
    ViewHolder viewHolder;

    if(convertView == null) {
        LayoutInflater inflater = myContext.getLayoutInflater();
        convertView = inflater.inflate(R.layout.lessons_list_item, null);

        viewHolder = new ViewHolder();
        viewHolder.postNameView = (TextView) convertView.findViewById(R.id.lessons_name);
        viewHolder.postDurationView = (TextView) convertView.findViewById(R.id.lessons_duration);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    //(position + 1) + ") " used to display 1) 2) 3) etc of lessons
    viewHolder.postNameView.setText((position + 1) + ") " + datas.get(position).getName());
    viewHolder.postDurationView.setText("Длительность: " + datas.get(position).getDuration().substring(0,8));

    return convertView;
}

static class ViewHolder{
    TextView postNameView;
    TextView postDurationView;
}
}

Method of finding height:

    public static void setListViewSize(AbsListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null)
        return;

    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.UNSPECIFIED);
    int totalHeight = 0;
    View view = null;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        view = listAdapter.getView(i, view, listView);
        if (i == 0)
            view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, AbsListView.LayoutParams.WRAP_CONTENT));

        view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
        totalHeight += view.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getMeasuredHeight() * (listAdapter.getCount() + 1));
    listView.setLayoutParams(params);
    listView.requestLayout();
}

Thats how I set the content of list:

    mAdapter = new LessonsItemAdapter(getActivity(),
            R.layout.lessons_list_item, parserJson.getLessons(courseUrl).getLessonsArray());

    // Set the adapter
    mListView = (AbsListView) view.findViewById(android.R.id.list);
    ((AdapterView<ListAdapter>) mListView).setAdapter(mAdapter);

    // Set OnItemClickListener so we can be notified on item clicks
    mListView.setOnItemClickListener(this);
    ListHelper.setListViewSize(mListView);

And thats the result:

enter image description here

The entire View is scrolling. But the last item always shows only by half. You see, the field Duration ("Длительность") is not showing. Although the last item of list is clicakble.

Please help me with that method of defining the total height. Thanks in advance. Appreciate any help.

Upvotes: 1

Views: 2423

Answers (3)

Bhavik Mehta
Bhavik Mehta

Reputation: 573

Your ListView in your layout file should be like

 <ListView android:id="@android:id/list"
            android:layout_width="match_parent"
             android:layout_height="wrap_content" 
            android:layout_below="@id/course_duration"/>

Now in your code where you want the ListView's height to be adjusted according to its children place the following method.

public static void setListViewHeightBasedOnChildren(ListView listView) {
            ListAdapter listAdapter = listView.getAdapter();
            if (listAdapter == null) {
                // pre-condition
                return;
            }

            int totalHeight = 0;
            for (int i = 0; i < listAdapter.getCount(); i++) {
                View listItem = listAdapter.getView(i, null, listView);
                listItem.measure(0, 0);
                totalHeight += listItem.getMeasuredHeight();
            }

            ViewGroup.LayoutParams params = listView.getLayoutParams();
            params.height = totalHeight
                    + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
            listView.setLayoutParams(params);
        }

just call it by passing your ListView inside it

  setListViewHeightBasedOnChildren(list);

Simple but powerful solution

Upvotes: 1

anil
anil

Reputation: 2123

try code below from this blog

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int newHeight = 0;
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    if (heightMode != MeasureSpec.EXACTLY) 
    {
        ListAdapter listAdapter = getAdapter();
        if (listAdapter != null && !listAdapter.isEmpty()) 
        {
            int listPosition = 0;
            for (listPosition = 0; listPosition < listAdapter.getCount()
                    && listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) 
            {
                View listItem = listAdapter.getView(listPosition, null, this);
                //now it will not throw a NPE if listItem is a ViewGroup instance
                if (listItem instanceof ViewGroup) 
                {
                    listItem.setLayoutParams(new LayoutParams(
                            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                }
                listItem.measure(widthMeasureSpec, heightMeasureSpec);
                newHeight += listItem.getMeasuredHeight();
            }
            newHeight += getDividerHeight() * listPosition;
        }
        if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) 
        {
            if (newHeight > heightSize) 
            {
                newHeight = heightSize;
            }
        }
    } 
    else 
    {
        newHeight = getMeasuredHeight();
    }
    setMeasuredDimension(getMeasuredWidth(), newHeight);
}

Upvotes: 0

Vilas
Vilas

Reputation: 1705

Use this piece of code. It will reset the size of listview according to number of items.

public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null)
        return;

    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(),
            MeasureSpec.UNSPECIFIED);
    int totalHeight = 0;
    View view = null;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        view = listAdapter.getView(i, view, listView);
        if (i == 0)
            view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth,
                    LayoutParams.WRAP_CONTENT));

        view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
        totalHeight += view.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight
            + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
    listView.requestLayout();
}

Upvotes: 1

Related Questions