简单的自定义ViewGroup

2017-07-23  本文已影响0人  笔墨Android

不怕跌倒,所以飞翔

今天有了一个感慨:静下心来去学习_总会有收获的!
其实开始的时候总觉得自己写不出来,但是静下心来了之后,还是写不出来,觉得自己都要放弃了,但是工作就是工作,没有你想不想,一定要去实现,没有别的只有实现,所以必须去弄,希望以后慢慢积累更多知识,不必在这么累。不墨迹了。。。

其实说实话自定义View没有想象的那么简单,今天就先记录一下吧,如果有时间自己在写一个专题来记录下这些内容吧!

先上张图片说明一下 效果图

效果就是点击的时候文字改变颜色,开始播放音乐,转盘开始旋转,再次点击取消旋转!

首先简单说下自己了解的自定义ViewGroup,其实就是重写onLayout()onMeasure()
还有就是重写一个返回LayoutParams的方法,以为每个ViewGroup都会返回一个LayoutParams,所以这个方法要重写的!但是看了几篇文章都是返回了一个 MarginLayoutParams(getContext(), attrs);或许是因为MarginLayoutParams可以设置边距的问题吧!

其实自定义ViewGroup分以下几个步骤:

generateLayoutParams()

重写这个方法基本上是返回一个对应的LayoutParams,因为每一个ViewGroup都会对应一个LayoutParams,所以必须重写这个方法,我看了很多都是返回一个MarginLayoutParams,至于为什么我也不太清楚,希望有知道的大神不吝赐教;

onMeasure()

说到这个方法的话,主要的作用就是当你定义xml时,你只要写了wrap_content的时候才会使用onMeasure();进行测量,绘制真是的尺寸,若你只想用match_parent那么大可以不用去操心这个方法;按照下面的写就可以了。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 计算出所有的childView的宽和高
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        //测量并保存layout的宽高(使用getDefaultSize时,wrap_content和match_perent都是填充屏幕)
        //稍后会重新写这个方法,能达到wrap_content的效果
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

onLayout()

这个方法要说的就会多点了,其实这个方法简单讲的话就是测量每一个子View的,然后对位置进行配置;但是这里基本上都涉及到一些算法问题,所以关于方法的问题基本上都是考验你算法功底的时候;

先说说我这个自定义的是什么吧!中间有一个圆形,其他的就是定义了一些随机数,用来摆放相应的TextView,但是要保证这些TextView不重叠,而且还不能和中间的圆形重叠,其实也算是很简单的呢。。。

其他的方法都在上面可以找到的就不写了。。其实这个ViewGroup最难点就在于怎么把确定它们之间不重叠的问题,其实刚开始在网上找了很多的办法,但是都不怎么好使,后来无意之间看到了Rect其实有一个静态方法就能判断两个Rect是否重复,所以问题就变得很简单了;不多逼逼了,还是看代码吧!

 int cCount = getChildCount();
        int screenWidth = getWidth();
        int screenHeight = getHeight();

        int cl = 0, ct = 0, cr = 0, cb = 0;
        for (int i = 0; i < cCount; i++) {
            View childAt = getChildAt(i);
            int cWidth = childAt.getMeasuredWidth();
            int cHeight = childAt.getMeasuredHeight();
            if (i == 0) {
                cl = screenWidth / 2 - cWidth / 2;
                ct = screenHeight / 2 - cHeight / 2;
                cr = screenWidth / 2 + cWidth / 2;
                cb = screenHeight / 2 + cHeight / 2;
                mRects.add(new Rect(cl,ct,cr,cb));
                childAt.layout(cl, ct, cr, cb);
            } else {/*这个是第一个View的时候,展示在中间的*/
                setLocationView(screenWidth, screenHeight, childAt, cWidth, cHeight);
            }
        }

    }

    private void setLocationView(int screenWidth, int screenHeight, View childAt, int cWidth, int cHeight) {
        int cl;
        int ct;
        int cr;
        int cb;
        /*这里随机的是结束点*/
        int randomWidth = mRandom.nextInt(screenWidth);
        int randomHeight = mRandom.nextInt(screenHeight);

        cl = randomWidth - cWidth;
        ct = randomHeight - cHeight;
        cr = randomWidth;
        cb = randomHeight;

        if (cl < 0 || ct < 0) {
            /*这里应该重新获取点重新计算*/
            setLocationView(screenWidth,screenHeight,childAt,cWidth,cHeight);
            return;
        }

        /*这里判断的是是否重合*/
        Rect currentRect = new Rect(cl, ct, cr, cb);
        for (int i = 0; i < mRects.size(); i++) {
            Rect rect = mRects.get(i);
            if(Rect.intersects(rect,currentRect)){
                setLocationView(screenWidth,screenHeight,childAt,cWidth,cHeight);
                return;
            }
        }
        childAt.layout(cl, ct, cr, cb);
        mRects.add(new Rect(cl,ct,cr,cb));
    }

其实最主要的一个方法就是Rect.intersects(rect,currentRect)这个方法,开始的时候不知道这个方法是静态的方法,还傻了吧唧的拿Rect的对象去调用呢,一直oom后来才看到这是一个静态的方法,改成Rect之后就没有在oom了!所以这一定要注意一下!

Demo地址

今天就先记录到这里吧!如果以后时间充裕的话一定要写一个关于自定义View的专题……

上一篇下一篇

猜你喜欢

热点阅读