简单的自定义ViewGroup
今天有了一个感慨:静下心来去学习_总会有收获的!
其实开始的时候总觉得自己写不出来,但是静下心来了之后,还是写不出来,觉得自己都要放弃了,但是工作就是工作,没有你想不想,一定要去实现,没有别的只有实现,所以必须去弄,希望以后慢慢积累更多知识,不必在这么累。不墨迹了。。。
其实说实话自定义View没有想象的那么简单,今天就先记录一下吧,如果有时间自己在写一个专题来记录下这些内容吧!
先上张图片说明一下 效果图效果就是点击的时候文字改变颜色,开始播放音乐,转盘开始旋转,再次点击取消旋转!
首先简单说下自己了解的自定义ViewGroup,其实就是重写onLayout()和onMeasure()
还有就是重写一个返回LayoutParams的方法,以为每个ViewGroup都会返回一个LayoutParams,所以这个方法要重写的!但是看了几篇文章都是返回了一个 MarginLayoutParams(getContext(), attrs);或许是因为MarginLayoutParams可以设置边距的问题吧!
其实自定义ViewGroup分以下几个步骤:
- 重写generateLayoutParams()
- 重写onMeasure()
- 重写onLayout()
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了!所以这一定要注意一下!
今天就先记录到这里吧!如果以后时间充裕的话一定要写一个关于自定义View的专题……