-
这个效果做起来好像没什么意义,如果不加监听回调 图片就能直接替代。写这篇博客的目的是锻炼一下思维能力,以更好的面多各种自定义view需求。
本文是和代码同步写的。也就是说在写文章的时候才敲的代码。这样会显得文章有些许混乱。但是我想这样记录下来,一个自定义view的真正的制作过程,是一点一点,一步步跟着思路的改变,完善的。不可能一下子就做出一个完整的view。。技术也是这样,不可能一步登天。都是一步一步的积累。
另外,每一篇博客都是建立在之前博客的基础知识上的,如果你刚接触自定义view。可以来说说自定义view简单学习的方式这里看我以前的文章。记录了我学习自定义view的过程,而且前几篇博客或多或少犯了一些错误。这里我并不想改正博文中的错误,因为些错误是大家经常会犯的,后来的博客都有指出这些错误,以及不再犯,这是一个学习的过程。所以我想把错误的经历记录下来。等成为高手 回头看看当年的自己是多么菜。。也会有成就感。。
老规矩效果图如下:

首先画一个六边形,画之前来计算一下六边形的相关知识:

假设一个正六边形的边长为a ,因为每个角都是120° 所以可得高为根号三a ,如图所示。
有了这些信息我们就可以绘制一个六边形出来,如下:
123456789floatheight = (float) (Math.sqrt(3)*mLength);mPath.moveTo(mLength/2,0);mPath.lineTo(0,height/2);mPath.lineTo(mLength/2,height);mPath.lineTo((float) (mLength*1.5),height);mPath.lineTo(2*mLength,height/2);mPath.lineTo((float) (mLength*1.5),0);mPath.lineTo(mLength/2,0);mPath.close();
绘制效果:
然后将其根据一个偏移量进行平移,就可以用循环绘制出多个六边形
这里offset是偏移量,紧挨着的话应该是偏移一个六边形的宽,宽由上图可知为 a/2+a+a/2 即 2a;
1234567891011for(inti =0; i <3;i++) {intoffset = mLength *2* i;mPath.moveTo(mLength /2+ offset,0);mPath.lineTo(0+ offset, height /2);mPath.lineTo(mLength /2+ offset, height);mPath.lineTo((float) (mLength *1.5) + offset, height);mPath.lineTo(2* mLength + offset, height /2);mPath.lineTo((float) (mLength *1.5)+offset,0);mPath.lineTo(mLength /2+offset,0);mPath.close();}
发现效果如下
这不对啊,很奇怪啊。。 底下空出来的一个三角形放不下我们的第二行啊。。
那么怎么办呢。。 加大offset! 加大多少呢。。 应该多增加一个边长。。这样就正好留空了。 来试试

现在来准备画第二行....
发现我们之前path的坐标都是相对写死的。。 所以要回过头改一下,改成给定一个起点,就可以绘制出一个六边形,经过计算,得出下图

这里a代表边长。
改完之后的代码是:
12345678910111213141516171819floatheight = (float) (Math.sqrt(3)*mLength);for(inti =0; i <3;i++) {//横坐标偏移量intoffset = mLength *3* i ;//左上角的xintx = mLength/2+ offset;inty =0;//根据左上角一点 绘制整个正六边形mPath.moveTo(x, y);mPath.lineTo(x -mLength/2, height /2+ y);mPath.lineTo(x, height+y);mPath.lineTo(x + mLength, height +y);mPath.lineTo((float) (x +1.5*mLength), height /2+y);mPath.lineTo(x + mLength, y);mPath.lineTo(x, y);mPath.close();}
绘制出来的效果是一样的。但是方法以及变了。然后来画第二行,第二行起点的path应该在这里

坐标是: 2a , height/2 这里的偏移量不变。
首先将画path的方法提取出来(as快捷键ctrl + alt + m)
然后再给个循环,来绘制第二行的六边形1234567891011//根据左上角一点 绘制整个正六边形privatevoidgetPath(floatheight,floatx,floaty) {mPath.moveTo(x, y);mPath.lineTo(x -mLength/2, height /2+ y);mPath.lineTo(x, height+y);mPath.lineTo(x + mLength, height +y);mPath.lineTo((float) (x +1.5*mLength), height /2+y);mPath.lineTo(x + mLength, y);mPath.lineTo(x, y);mPath.close();}得到如下的效果。1234567891011for(inti =0;i<2;i++){floatoffset = mLength *3* i ;floatx = mLength*2+ offset;floaty = height/2;getPath(height,x,y);}canvas.drawPath(mPath,mPaint);
现在ondraw的全部代码如下:
12345678910111213141516171819202122232425262728293031323334@OverrideprotectedvoidonDraw(Canvas canvas) {mPaint.setColor(Color.parseColor("#FFBB33"));//正六边形的高floatheight = (float) (Math.sqrt(3)*mLength);for(inti =0; i <3;i++) {//横坐标偏移量floatoffset = mLength *3* i ;//左上角的xfloatx = mLength/2+ offset;floaty =0;getPath(height, x, y);}canvas.drawPath(mPath,mPaint);mPath.reset();mPaint.setColor(Color.parseColor("#AA66CC"));for(inti =0;i<2;i++){floatoffset = mLength *3* i ;floatx = mLength*2+ offset;floaty = height/2;getPath(height,x,y);}canvas.drawPath(mPath,mPaint);}
接下来对每行的个数进行一下控制。12345//每行的个数privateintmColumnsCount =3;//行数privateintmLineCount =3;
对应的循环也改变,最外面套一个大循环,来控制多行绘制现在整个ondraw如下。1234for(intj =0; j < mLineCount; j++) {if(j%2==0) 绘制奇数行else绘制偶数行}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647@OverrideprotectedvoidonDraw(Canvas canvas) {//正六边形的高floatheight = (float) (Math.sqrt(3) * mLength);for(intj =0; j < mLineCount; j++) {if(j %2==0) {mPaint.setColor(Color.parseColor("#FFBB33"));for(inti =0; i < mColumnsCount; i++) {//横坐标偏移量floatoffset = mLength *3* i;//左上角的xfloatx = mLength /2+ offset;floaty = j * height /2;getPath(height, x, y);}canvas.drawPath(mPath, mPaint);mPath.reset();}else{mPaint.setColor(Color.parseColor("#AA66CC"));for(inti =0; i < mColumnsCount; i++) {floatoffset = mLength *3* i;floatx = mLength *2+ offset;floaty = (height /2) * j;getPath(height, x, y);}canvas.drawPath(mPath, mPaint);mPath.reset();}}}
好像颜色一样就不好看了。。那我们来动态改变一下颜色..
添加一个属性list来存放color
1privateArrayList<integer> mColorList;</integer>在循环中,取出颜色值1234567891011mColorList =newArrayList<>();mColorList.add(Color.parseColor("#33B5E5"));mColorList.add(Color.parseColor("#AA66CC"));mColorList.add(Color.parseColor("#99CC00"));mColorList.add(Color.parseColor("#FFBB33"));mColorList.add(Color.parseColor("#FF4444"));效果如下:123for(intj =0; j < mLineCount; j++) {mPaint.setColor(mColorList.get(j));
嗯。。看起来像一点样子了。。。 给中间加点文字吧。。
先给每个蜂窝编号

按上面的循环 j为行数 i为列数
研究规律发现 编号等于 j*3 + i
我们有六边形左上角的坐标xy 可以轻易的计算出中心坐标

这些都有了。开一个list存放中间的文字:
在初始化的时候给添加点数据12//存放文字的listprivateArrayList<string> mTextList ;</string>123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138mTextList =newArrayList<>();for(inti =0;i<mlinecount*mcolumnscount;i++){ mtextpaint="new"pre=""wing="">绘制文字: 这里要注意他和path的绘制顺序,如果path后绘制则会覆盖掉文字<preclass="brush:java;">floattxtLength = mTextPaint.measureText(mTextList.get(txtId));canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);</pre><p>下面是全部的ondraw</p><preclass="brush:java;">@OverrideprotectedvoidonDraw(Canvas canvas) {//正六边形的高floatheight = (float) (Math.sqrt(3) * mLength);for(intj =0; j < mLineCount; j++) {mPaint.setColor(mColorList.get(j));if(j %2==0) {// mPaint.setColor(Color.parseColor("#FFBB33"));for(inti =0; i < mColumnsCount; i++) {inttxtId = j*3+i;//横坐标偏移量floatoffset = mLength *3* i;//左上角的xfloatx = mLength /2+ offset;floaty = j * height /2;mPath.reset();getPath(height, x, y);canvas.drawPath(mPath, mPaint);floattxtLength = mTextPaint.measureText(mTextList.get(txtId));canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);}}else{// mPaint.setColor(Color.parseColor("#AA66CC"));for(inti =0; i < mColumnsCount; i++) {inttxtId = j*3+i;floatoffset = mLength *3* i;floatx = mLength *2+ offset;floaty = (height /2) * j;mPath.reset();getPath(height, x, y);canvas.drawPath(mPath, mPaint);floattxtLength = mTextPaint.measureText(mTextList.get(txtId));canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);}}}}</pre><br>现在的效果图如下:<p><img alt="\" src="http://www.2cto.com/uploadfile/Collfiles/20160125/20160125091503178.jpg" style="width: 377px; height: 453px;"></p><p>好,那现在让他灵活一点。添加各种set方法,比如行数啊 列数啊 边长啊 文字内容啊 颜色啊之类的。</p><preclass="brush:java;">/*** 设置列数* @param mColumnsCount*/publicvoidsetColumnsCount(intmColumnsCount) {this.mColumnsCount = mColumnsCount;invalidate();}/*** 设置行数* @param mLineCount*/publicvoidsetLineCount(intmLineCount) {this.mLineCount = mLineCount;invalidate();}/*** 设置文本数据*/publicvoidsetTextList(ArrayList<string> textList) {mTextList.clear();mTextList.addAll(textList);invalidate();}/*** 设置颜色数据* @param colorList*/publicvoidsetColorList(ArrayList<integer> colorList) {mColorList.clear();mColorList.addAll(colorList);invalidate();}</integer></string></pre>然后 你有没有忘记测量呢? 只要把最外面的矩形大小给他就行<preclass="brush:java;">@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {intwidthSize = MeasureSpec.getSize(widthMeasureSpec);intwidthMode = MeasureSpec.getMode(widthMeasureSpec);intheightSize = MeasureSpec.getSize(heightMeasureSpec);intheightMode = MeasureSpec.getMode(heightMeasureSpec);if(widthMode == MeasureSpec.AT_MOST){widthSize = (int) ((3f*mColumnsCount+0.5f) *mLength);}else{// throw new IllegalStateException("only support wrap_content");}if(heightMode == MeasureSpec.AT_MOST){heightSize = (int) ((mLineCount/2f +0.5f) * (Math.sqrt(3) * mLength));}else{// throw new IllegalStateException("only support wrap_content");}setMeasuredDimension(widthSize,heightSize);}</pre><p>这下使用wrap_content 来看看view的大小:</p><p><img alt="\" src="http://www.2cto.com/uploadfile/Collfiles/20160125/20160125091504190.jpg" style="width: 426px; height: 473px;"></p><p>嗯。。测量也对着。。。 这里我只实现了wrap_content 大家可以以及扩展 让他支持EXACTLY</p>
自定义view详解,手把手带你画一个漂亮蜂窝view Android自定义view
转自:http://www.2cto.com/kf/201601/487139.html

被折叠的 条评论
为什么被折叠?



