ScrollView嵌套GridView冲突解析

    最近项目开发中,用到了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介绍

你可能感兴趣的:(GridView,scrollview,自定义控件,View嵌套)