根据其中的多行文本视图动态设置 ListView 高度

Set ListView Height dynamically based on multiline textview inside it

我正在使用基本适配器在列表视图中动态设置数据。我试图动态设置列表视图高度。如果其中的文本视图是单行,它就可以完美地工作。但是,如果 textview 是多行的,则高度设置不正确。高度设置仅考虑单行文本视图。如何正确设置包含多行文本视图的列表视图项目的高度。这是代码:

片段代码:

ListView mlistNews=(ListView)rootView.findViewById(R.id.news_listView);
mlistNews.setAdapter(new NewsAdapter(getActivity(),params_news));
Utils.setListViewHeightBasedOnItems(mlistNews);

效用函数:

public static boolean setListViewHeightBasedOnItems(ListView listView) {

    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter != null) {

        int numberOfItems = listAdapter.getCount();

        // Get total height of all items.
        int totalItemsHeight = 0;
        for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
            View item = listAdapter.getView(itemPos, null, listView);
            item.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            totalItemsHeight += item.getMeasuredHeight();
        }

        // Get total height of all item dividers.
        int totalDividersHeight = listView.getDividerHeight() *
                (numberOfItems - 1);
        // Get padding
        int totalPadding = listView.getPaddingTop() + listView.getPaddingBottom();

        // Set list height.
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalItemsHeight + totalDividersHeight + totalPadding;
        listView.setLayoutParams(params);
        listView.requestLayout();

        return true;

    } else {
        return false;
    }

}

dashboard_list_news.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<TextView
    android:layout_width="0dp"
    android:id="@+id/news_item_text"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:layout_gravity="left|center_vertical"
    android:layout_marginLeft="5dp"/>

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/chevron"
    android:layout_gravity="center_vertical|right"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="10dp" />

</LinearLayout>

列表视图:

<ListView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/rounded_shape_list"
            android:id="@+id/news_listView"
            android:paddingTop="5dp"
            android:paddingBottom="5dp"
            android:divider="#6DCB99"
            android:dividerHeight="1dp" />

问题可能是这个电话:

item.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))

这里你没有限制宽度,所以 TextView 扩展到它需要的任何宽度,以在一行中显示所有文本。因此,您将始终获得等于单行文本的高度? 我认为您应该将此处的宽度限制为列表视图中可用的宽度。

正如 Teemu 提到的,您需要限制宽度。下面的示例代码。

float px = 300 * (listView.getResources().getDisplayMetrics().density);
item.measure(View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

您可以尝试使用此自定义列表视图以避免 listhiight 出现多行文本视图问题

 <namespace.epicurio.NestedListView
           android:id="@+id/listComments"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:layout_marginBottom="2dp"
           android:divider="#000000"
           android:dividerHeight="1.0sp">
         </namespace.epicurio.NestedListView>


    public class NestedListView extends ListView implements OnTouchListener, OnScrollListener {

        private int listViewTouchAction;
        private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;

        public NestedListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            listViewTouchAction = -1;
            setOnScrollListener(this);
            setOnTouchListener(this);
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
                if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
                    scrollBy(0, -1);
                }
            }
        }

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
        }

        @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);
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
                if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
                    scrollBy(0, 1);
                }
            }
            return false;
        }
    }

试试这个代码:

listview.post(new Runnable() {
    @Override
    public void run() {
        calculateListHeight(listview.getWidth());
    }
});

public void calculateListHeight(int width) {
    final ListAdapter adapter = listview.getAdapter();

    // Calculate the height of the ListView to display all items
    int totalHeight = listview.getPaddingTop() + listview.getPaddingBottom();
    for (int i = 0; i < adapter.getCount(); i++) {
        View item = adapter.getView(i, null, this);
        item.measure(
                View.MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
                View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
        );
        totalHeight += item.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listview.getLayoutParams();
    params.height = totalHeight + (listview.getDividerHeight() * (adapter.getCount() - 1));

    listview.setLayoutParams(params);
    listview.requestLayout();
}

@AlexanderAgeichenko 这是我与@baradas 和问题

的实现
        int totalItemsHeight = 0;
        float px =  (customListView.getResources().getDisplayMetrics().density);
        totalItemsHeight = (int)px;
        Log.d(YOUR_TAG, " datta forloop ...  px " + px);
        Log.d(YOUR_TAG, " datta forloop ...  totalItemsHeight = (int)px=  " + totalItemsHeight);
        for (int itemPos = 0; itemPos < datta.length(); itemPos++) {
            View item = CustomListAdptr.getView(itemPos, null, customListView);
////            item.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
////                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            item.getMeasuredHeightAndState();
            Log.d(YOUR_TAG, " datta forloop item.getHeight() " + item.getHeight());
            Log.d(YOUR_TAG, " datta forloop item.getMeasuredHeight() " + item.getMeasuredHeight());
            Log.d(YOUR_TAG, " datta forloop item.getMeasuredHeightAndState() " + item.getMeasuredHeightAndState());
            int itmHeight = item.getHeight();
            Log.d(YOUR_TAG, " datta forloop ...  itmHeight " + itmHeight);
            item.measure(View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            totalItemsHeight = item.getMeasuredHeight();
//            Log.d(YOUR_TAG, " datta forloop ...  item.getMeasuredHeight() " + item.getMeasuredHeight());
            Log.d(YOUR_TAG, " datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  " + totalItemsHeight);
        }
        Log.d(YOUR_TAG, " datta forloop ...  totalItemsHeight ==  " + totalItemsHeight);

        // Get total height of all item dividers.
        int totalDividersHeight = customListView.getDividerHeight() *
                (numberOfItems - 1);
        // Get padding
        int totalPadding = customListView.getPaddingTop() + customListView.getPaddingBottom();

        // Set list height.
        ViewGroup.LayoutParams params = customListView.getLayoutParams();
        params.height = totalItemsHeight + totalDividersHeight + totalPadding;
        customListView.setLayoutParams(params);
        customListView.requestLayout();
        customListView.canScrollList(0);

输出结果是

D/YOUR_TAG:  onViewCompleted() if(success) setting the list data
D/YOUR_TAG:  datta counts 3
D/YOUR_TAG:  datta forloop ...  px 2.0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight = (int)px=  2
D/YOUR_TAG:  datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG:  datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG:  datta forloop item.getHeight() 0
D/YOUR_TAG:  datta forloop ...  itmHeight 0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  1709
D/YOUR_TAG:  datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG:  datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG:  datta forloop item.getHeight() 0
D/YOUR_TAG:  datta forloop ...  itmHeight 0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  1709
D/YOUR_TAG:  datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG:  datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG:  datta forloop item.getHeight() 0
D/YOUR_TAG:  datta forloop ...  itmHeight 0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  1709
D/YOUR_TAG:  datta forloop ...  totalItemsHeight ==  1709
D/YOUR_TAG:  getView() -> unit_option= 0 :: class java.lang.String

有 110 float px = 110 *(customListView.getResources().getDisplayMetrics().density);

D/YOUR_TAG:  onViewCompleted() if(success) setting the list data
D/YOUR_TAG:  datta counts 3
D/YOUR_TAG:  datta forloop ...  px 220.0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight = (int)px=  220
D/YOUR_TAG:  datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG:  datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG:  datta forloop item.getHeight() 0
D/YOUR_TAG:  datta forloop ...  itmHeight 0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  159
D/YOUR_TAG:  datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG:  datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG:  datta forloop item.getHeight() 0
D/YOUR_TAG:  datta forloop ...  itmHeight 0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  159
D/YOUR_TAG:  datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG:  datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG:  datta forloop item.getHeight() 0
D/YOUR_TAG:  datta forloop ...  itmHeight 0
D/YOUR_TAG:  datta forloop ...  totalItemsHeight=item.getMeasuredHeight()  159
D/YOUR_TAG:  datta forloop ...  totalItemsHeight ==  159