scrollview嵌套listview导致listview只显示一行的终极解决方案

  • 在开发的过程当中,由于手机屏幕的大小的限制,我们经常需要使用滑动的方式,来显示更多的内容。在最近的工作中,遇见一个需求,需要将ListView嵌套到ScrollView中显示。于是乎有了如下布局: 

    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   
    2.     xmlns:tools="http://schemas.android.com/tools"   
    3.     android:layout_width="match_parent"   
    4.     android:layout_height="match_parent"   
    5.     android:background="#FFE1FF"   
    6.     android:orientation="vertical" >   
    7.     <ScrollView   
    8.         android:layout_width="match_parent"   
    9.         android:layout_height="match_parent" >   
    10.         <LinearLayout   
    11.             android:layout_width="match_parent"   
    12.             android:layout_height="match_parent" >   
    13.             <ListView   
    14.                 android:id="@+id/listView1"   
    15.                 android:layout_width="match_parent"   
    16.                 android:layout_height="match_parent"   
    17.                 android:fadingEdge="vertical"   
    18.                 android:fadingEdgeLength="5dp" />   
    19.         </LinearLayout>   
    20.     </ScrollView>   
    21. </LinearLayout>   

    运行程序,如下结果,无论你如何调整layout_width,layout_height属性,ListView列表只显示一列 


    在查阅的各种文档和资料后,发现在ScrollView中嵌套ListView空间,无法正确的计算ListView的大小,故可以通过代码,根据当前的ListView的列表项计算列表的尺寸。实现代码如下: 

    1. public class MainActivity extends Activity {   
    2.     private ListView listView;   
    3.     @Override   
    4.     protected void onCreate(Bundle savedInstanceState) {   
    5.         super.onCreate(savedInstanceState);   
    6.         setContentView(R.layout.activity_main);   
    7.         listView = (ListView) findViewById(R.id.listView1);   
    8.         String[] adapterData = new String[] { "Afghanistan""Albania",… … "Bosnia"};   
    9.         listView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,adapterData));   
    10.         setListViewHeightBasedOnChildren(listView);   
    11.     }   
    12.     public void setListViewHeightBasedOnChildren(ListView listView) {   
    13.         // 获取ListView对应的Adapter   
    14.         ListAdapter listAdapter = listView.getAdapter();   
    15.         if (listAdapter == null) {   
    16.             return;   
    17.         }   
    18.    
    19.         int totalHeight = 0;   
    20.         for (int i = 0, len = listAdapter.getCount(); i < len; i++) {   
    21.             // listAdapter.getCount()返回数据项的数目   
    22.             View listItem = listAdapter.getView(i, null, listView);   
    23.             // 计算子项View 的宽高   
    24.             listItem.measure(00);    
    25.             // 统计所有子项的总高度   
    26.             totalHeight += listItem.getMeasuredHeight();    
    27.         }   
    28.    
    29.         ViewGroup.LayoutParams params = listView.getLayoutParams();   
    30.         params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));   
    31.         // listView.getDividerHeight()获取子项间分隔符占用的高度   
    32.         // params.height最后得到整个ListView完整显示需要的高度   
    33.         listView.setLayoutParams(params);   
    34.     }   
    35. }   
    运行结果,OK问题搞定,打完收工 

BUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!这个代码里面有一个问题,就是这个当你的ListView里面多行的TextView的话,ListView的高度就会计算错误,它只算到了一行TextView的高度,导致listview最后一项显示不全!

  • 1、前言
  • 从谷歌那里找到的ScrollView嵌套ListView只显示一行的解决办法相信很多人都遇到过,然后大部分都是用这位博主的办法解决的吧

    刚开始我也是用这个办法解决的,首先感谢这位哥的大私奉献,贴上地址

    http://blog.csdn.net/p106786860/article/details/10461015

    2、解决的核心代码

     

    01. public void setListViewHeightBasedOnChildren(ListView listView) {  
    02. // 获取ListView对应的Adapter  
    03. ListAdapter listAdapter = listView.getAdapter();  
    04. if (listAdapter == null) {  
    05. return;  
    06. }  
    07.  
    08. int totalHeight = 0;  
    09. for (int i = 0, len = listAdapter.getCount(); i < len; i++) {  
    10. // listAdapter.getCount()返回数据项的数目  
    11. View listItem = listAdapter.getView(i, null, listView);  
    12. // 计算子项View 的宽高  
    13. listItem.measure(0, 0);   
    14. // 统计所有子项的总高度  
    15. totalHeight += listItem.getMeasuredHeight();   
    16. }  
    17.  
    18. ViewGroup.LayoutParams params = listView.getLayoutParams();  
    19. params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));  
    20. // listView.getDividerHeight()获取子项间分隔符占用的高度  
    21. // params.height最后得到整个ListView完整显示需要的高度  
    22. listView.setLayoutParams(params);  
    23. }
    这个代码让控件去计算Listview自己的高度然后设置这个Listview的高度

     

    但是这个代码里面有一个问题,就是这个当你的ListView里面有多行的TextView的话,ListView的高度就会计算错误,它只算到了一行TextView的高度,

    这个问题在so上的概述为以下:

    http://stackoverflow.com/questions/14386584/getmeasuredheight-of-textview-with-wrapped-text

    3、终极解决办法

    这个问题头疼了一阵后,查找了一下,应该自定义自己的textview,然后重写一个TextView的onMeasure方法比较好解决

    代码有

     

    public class TextViewHeightPlus extends TextView {
        private static final String TAG = "TextView";
        private Context context;
        private int actualHeight = 0;

        public int getActualHeight() {
            return actualHeight;
        }

        public TextViewHeightPlus(Context context) {
            super(context);
            this.context = context;
        }

        public TextViewHeightPlus(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.context = context;
        }

        public TextViewHeightPlus(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            this.context = context;
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            actualHeight = 0;

            actualHeight = (int) ((getLineCount() - 1) * getTextSize());

        }

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

            Layout layout = getLayout();
            if (layout != null) {
                int height = (int) FloatMath.ceil(getMaxLineHeight(this.getText().toString())) + getCompoundPaddingTop()
                        + getCompoundPaddingBottom();
                int width = getMeasuredWidth();
                setMeasuredDimension(width, height);
            }
        }

        private float getMaxLineHeight(String str) {
            float height = 0.0f;
            float screenW = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth();
            float paddingLeft = ((RelativeLayout) this.getParent()).getPaddingLeft();
            float paddingReft = ((RelativeLayout) this.getParent()).getPaddingRight();
            //这里具体this.getPaint()要注意使用,要看你的TextView在什么位置,这个是拿TextView父控件的Padding的,为了更准确的算出换行
            int line = (int) Math.ceil((this.getPaint().measureText(str) / (screenW - paddingLeft - paddingReft)));
            height = (this.getPaint().getFontMetrics().descent - this.getPaint().getFontMetrics().ascent) * line;
            return height;
        }
    }

    然后listview的 item中内容textview就使用自定义的这个textview,item.xml如下:
  •  <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="5dp"
            android:paddingTop="5dp"
            android:paddingLeft="5dp"
             >

            <TextView
                android:id="@+id/titleTv"
                style="@style/titleTextSizeWithBlack"
                android:layout_marginLeft="5dp"
                android:textColor="@color/blog_item_time_text_new"
                android:textSize="@dimen/room_detail_name_textsize" />

            <com.itcalf.renhe.context.room.TextViewHeightPlus
                android:id="@+id/infoTv"
                style="@style/titleTextSizeWithBlack"
                android:layout_width="fill_parent"
                android:layout_below="@id/titleTv"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:textColor="@color/color333"
                android:textSize="@dimen/renhe_listview_item_content_textsize" />

            <TextView
                android:id="@+id/timeTv"
                style="@style/titleTextSizeWithBlack"
                android:layout_below="@+id/infoTv"
                android:layout_marginLeft="5dp"
                android:textColor="@color/color999"
                android:textSize="@dimen/renhe_listview_item_date_textsize" />
        </RelativeLayout>

     

    上面的代码完成更能为,在ListView开始测量时,测量到TextView时,就调用我们的onMeasure方法,我们就可以测量字体的总宽度除与去掉边距的屏幕的大小,就可以算出文字要几行来显示,然后测量字体的高度*行数可以得到字体的总高度,然后在加上上下边距就是TextView真正的高度,然后setMeasuredDimension进去就可以计算出正确的值出来。

     

    4、这下就真的打完收工了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值