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

Posted

技术标签:

【中文标题】根据里面的多行文本视图动态设置 ListView 高度【英文标题】:Set ListView Height dynamically based on multiline textview inside it 【发布时间】:2015-05-27 08:17:37 【问题描述】:

我正在使用基本适配器在列表视图中动态设置数据。我试图动态设置列表视图高度。如果里面的文本视图是单行的,它就可以完美地工作。但是,如果 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_
android:layout_
android:padding="5dp">
<TextView
    android:layout_
    android:id="@+id/news_item_text"
    android:layout_weight="1"
    android:layout_
    android:layout_gravity="left|center_vertical"
    android:layout_marginLeft="5dp"/>

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

</LinearLayout>

列表视图:

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

【问题讨论】:

您可以通过为 TextView 设置特定高度或尝试为 textview 设置最大行数功能来保持相同高度的列表视图行。 不要设置列表项高度。因为如果它的高度是包装内容,那么我认为它是自动调整行高。 @KarthikaPB Textview 内容是动态的,由适配器插入。根据内容,它可以是单行或多行。 @nlmm01 您应该采用两种建议的方法中的任何一种来保持相等的列表视图行 我不希望 listview 行的高度相同。它取决于内容。此外,我担心的是列表视图本身的高度,而不是项目。在原始问题中发布屏幕截图以显示问题。 【参考方案1】:

正如 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));

【讨论】:

为什么是 300 ?这个数字是什么意思? @AlexanderAgeichenko 看看我的回答***.com/questions/29225539/…【参考方案2】:

问题可能是这个电话:

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

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

【讨论】:

我应该如何改变宽度。举个例子会有帮助。【参考方案3】:

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

 <namespace.epicurio.NestedListView
           android:id="@+id/listComments"
           android:layout_
           android:layout_
           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;
        
    

【讨论】:

【参考方案4】:

试试这个代码:

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();

【讨论】:

【参考方案5】:

为@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

【讨论】:

getMeasuredHeight 在全局布局内容更改时生效...意味着添加/删除/移动/隐藏任何视图的可见性(仅限 GONE)...

以上是关于根据里面的多行文本视图动态设置 ListView 高度的主要内容,如果未能解决你的问题,请参考以下文章

在视图中动态添加多行标签

返回 listView 的最后一个元素并将其设置为文本视图 - 落在 NullPointerException

以编程方式动态调整多行 UILabel 和随附的表格视图单元格

根据android中的长度文本更改listview行的高度

Kivy listview 文本对齐

ListView 包含一个多行文本字段,后跟 Flutter 中的 ListTiles