您的位置:首页 > 其它

ScrollView嵌套ListView或GridView等,使得其高度自适应解决方案

2017-07-31 09:03 211 查看
这类的文章有很多,写此文的目的是为了备忘吧。ScrollView里面嵌套ListView或GridView等,两个View都有滚动的效果,在嵌套使用时起了冲突,一般不建议两者套用。解决的方案有很多但是最优的解决方案如下:
package com.base.frame.view;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

public class MyListView extends ListView {

public MyListView(Context context) {
super(context);
}

public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

/**
* 重写该方法,达到使ListView适应ScrollView的效果(因为listview的高度是不确定的,所以每次要重新测量)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
原理解析:了解自定义view 的肯定知道 onMeasure()是什么意思,makeMeasureSpec()方法中 Integer.MAX_VALUE >> 2在Android中,一个控件所占的模式和大小是通过一个整数int来表示的,这里很多同学就疑惑了,一个int值是怎么来表示模式的大小的,这里来看一张图片:原来,Android里面把int的最高2两位来表示模式,最低30位来表示大小。测量View大小使用的是onMeasure函数,我们可以从onMeasure的两个参数中取出宽高的相关数据:
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthsize = MeasureSpec.getSize(widthMeasureSpec);      //取出宽度的确切数值int widthmode = MeasureSpec.getMode(widthMeasureSpec);      //取出宽度的测量模式int heightsize = MeasureSpec.getSize(heightMeasureSpec);    //取出高度的确切数值int heightmode = MeasureSpec.getMode(heightMeasureSpec);    //取出高度的测量模式}
从上面可以看出 onMeasure 函数中有 widthMeasureSpec 和 heightMeasureSpec 这两个 int 类型的参数, 毫无疑问他们是和宽高相关的, 但它们其实不是宽和高, 而是由宽、高和各自方向上对应的测量模式来合成的一个值:测量模式一共有三种, 被定义在 Android 中的 View 类的一个内部类View.MeasureSpec中:3种模式1):UNSPECIFIED模式,官方意思是:父布局没有给子布局强加任何约束,子布局想要多大就要多大,说白了就是不确定大小2)EXACTLY模式,官方意思是:父布局给子布局限定了准确的大小,子布局的大小就是精确的,父亲给多大就是多大3)AT_MOST模式,官方意思是:父布局给定了一个最大的值,子布局的大小不能超过这个值,当然可以比这个值小privatestatic finalint MODE_SHIFT = 30;publicstatic finalint UNSPECIFIED = 0 << MODE_SHIFT;publicstatic finalint EXACTLY = 1 << MODE_SHIFT;publicstatic finalint AT_MOST = 2 << MODE_SHIFT; 不确定模式是0左移30位,也就是int类型的最高两位是00精确模式是1左移30位,也就是int类型的最高两位是01最大模式是是2左移30位,也就是int类型的最高两位是10所以调用了makeMeasureSpec方法,这个方法是用来生成一个带有模式和大小信息的int值的,第一个参数Integer.MAX_VALUE >> 2,这个参数是传的一个大小值,为什么是这个值呢,我们现在已经知道了,我们要生成的控件,它的大小最大值是int的最低30位的最大值,我们先取Integer.MAX_VALUE来获取int值的最大值,然后左移2位就得到这个临界值最大值了当然,我们在手机上的控件的大小不可能那么大,极限值就那么大,实际肯定比那个小,所以这个模式就得选择MeasureSpec.AT_MOST了,最后将生成的这个大小传递给父控件就可以了,super.onMeasure(widthMeasureSpec, expandSpec),这个函数只改变的是控件的高度,宽度没有改变,实际开发当中不管listview有多少条数据,都能一次性展现出来。最后选用第三种方式完美实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息