最近项目开发中,用到了ScrollView中嵌套GridView的情况,但是这两个View都是带有滚动的,当把其中一个嵌套到另一个里面的时候(例如我将GridView嵌套到ScrollView里面),就会出现冲突了,表现为GirdView显示不全。
解决方法也比较简单,只需要我们重新定义GridView,即自定义一个GridView,重写里面的onMeasure()方法:
public class MyGridView extends GridView {
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
在这里重写了onMeasure()方法,目的是为了使GridView不会出现滚动,这个方法也适用于和ListView的嵌套。剩下的就基本上没什么变化了,在布局文件中使用自定义的GridView就可以了,这里就不在粘代码了。
OnMeasure()方法解析:
在自定义View的时候,我们是如何将一个View成功的画在了所指定的位置的呢?看看Android关于View的源码,就会发现,onMeasure()、onLayout()、onDraw()这三个方法来确定View的外观,即onMeasure()方法决定了该View本身的大小、而子View在ViewGroup中的位置由onLayout()方法来确定,至于剩下的绘制View,就交给onDraw()方法了,这个方法我们还是相对比较熟悉的,毕竟初学者自定义View的时候,基本都只是重写onDraw()方法,在里面绘制内容。
这里我截取了一段TextView.java中的onMeasure()的源码:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
...
if (widthMode == MeasureSpec.EXACTLY) {
// Parent has told us how big to be. So be it.
width = widthSize;
} else {
if (mLayout != null && mEllipsize == null) {
des = desired(mLayout);
}
...
setMeasuredDimension(width, height);
关于里面的具体绘制我在这里就不详细的去解释了,涉及的内容比较复杂,如果不是专门去研究深层的我们只要知道怎么做就行了。
widthMeasureSpec,heightMeasureSpec这两个参数其实是有该View的父View传过来的,而子View的这两个值由父View和他们本身的一些属性来决定,如父View的layout_width,layout_height和padding以及子View本身的layout_margin共同决定。
通过这两参数来获取specMode和specSize,完事之后调用最后一行的setMeasuredDimension()来绘制,传入的参数才是真正决定View视图大小的值。
我们知道在父View中,给子View分配的空间大小并不是确定的,有可能随着具体的变化而变化,而这个变化的条件就是传到specMode中决定的,specMode一共有三种可能:
MeasureSpec.EXACTLY:父视图希望子视图的大小应该是specSize中指定的。
MeasureSpec.AT_MOST:子视图的大小最多是specSize中指定的值,也就是说不建议子视图的大小超过specSize中给定的值。
MeasureSpec.UNSPECIFIED:我们可以随意指定视图的大小。
这些值与具体的xml布局中的那些宽高设置是怎么对应的,我也没有去仔细研究,后面给出两个链接大家可以参考看一下,其实说白了也就是重新定义了父View能够给你子View的大小重新定义了一下,不再由父View的默认方法去定义,以达到我们想要的效果。
http://blog.csdn.net/u012604322/article/details/17093421 //关于重写onMeasure()方法的
http://blog.csdn.net/zjl5211314/article/details/6952698 // 关于MeasureSpec介绍