手把手带你画一个漂亮蜂窝view Android自定义view
上一篇做了一個(gè)水波紋view ?不知道大家有沒有動(dòng)手試試呢點(diǎn)擊打開鏈接
這個(gè)效果做起來(lái)好像沒什么意義,如果不加監(jiān)聽回調(diào) 圖片就能直接替代。寫這篇博客的目的是鍛煉一下思維能力,以更好的面多各種自定義view需求。
轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/wingichoy/article/details/50554058
本文是和代碼同步寫的。也就是說(shuō)在寫文章的時(shí)候才敲的代碼。這樣會(huì)顯得文章有些許混亂。但是我想這樣記錄下來(lái),一個(gè)自定義view的真正的制作過(guò)程,是一點(diǎn)一點(diǎn),一步步跟著思路的改變,完善的。不可能一下子就做出一個(gè)完整的view。。技術(shù)也是這樣,不可能一步登天。都是一步一步的積累。
另外,每一篇博客都是建立在之前博客的基礎(chǔ)知識(shí)上的,如果你剛接觸自定義view。可以來(lái)說(shuō)說(shuō)自定義view簡(jiǎn)單學(xué)習(xí)的方式這里看我以前的文章。記錄了我學(xué)習(xí)自定義view的過(guò)程,而且前幾篇博客或多或少犯了一些錯(cuò)誤。這里我并不想改正博文中的錯(cuò)誤,因?yàn)樾╁e(cuò)誤是大家經(jīng)常會(huì)犯的,后來(lái)的博客都有指出這些錯(cuò)誤,以及不再犯,這是一個(gè)學(xué)習(xí)的過(guò)程。所以我想把錯(cuò)誤的經(jīng)歷記錄下來(lái)。等成為高手 回頭看看當(dāng)年的自己是多么菜。。也會(huì)有成就感。。
老規(guī)矩效果圖如下:
首先畫一個(gè)六邊形,畫之前來(lái)計(jì)算一下六邊形的相關(guān)知識(shí):
假設(shè)一個(gè)正六邊形的邊長(zhǎng)為a ?,因?yàn)槊總€(gè)角都是120° ?所以可得高為根號(hào)三a ?,如圖所示。
有了這些信息我們就可以繪制一個(gè)六邊形出來(lái),如下:
繪制效果:
然后將其根據(jù)一個(gè)偏移量進(jìn)行平移,就可以用循環(huán)繪制出多個(gè)六邊形
這里offset是偏移量,緊挨著的話應(yīng)該是偏移一個(gè)六邊形的寬,寬由上圖可知為 a/2+a+a/2 即 2a;?
for(int i = 0 ; i < 3;i++) {int offset = 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();}發(fā)現(xiàn)效果如下
這不對(duì)啊,很奇怪啊。。 底下空出來(lái)的一個(gè)三角形放不下我們的第二行啊。。
那么怎么辦呢。。 加大offset! ?加大多少呢。。 應(yīng)該多增加一個(gè)邊長(zhǎng)。。這樣就正好留空了。 來(lái)試試
現(xiàn)在來(lái)準(zhǔn)備畫第二行....
發(fā)現(xiàn)我們之前path的坐標(biāo)都是相對(duì)寫死的。。 所以要回過(guò)頭改一下,改成給定一個(gè)起點(diǎn),就可以繪制出一個(gè)六邊形,經(jīng)過(guò)計(jì)算,得出下圖
這里a代表邊長(zhǎng)。
改完之后的代碼是:
float height = (float) (Math.sqrt(3)*mLength);for(int i = 0 ; i < 3;i++) {//橫坐標(biāo)偏移量int offset = mLength * 3 * i ;//左上角的xint x = mLength/2 + offset;int y = 0;//根據(jù)左上角一點(diǎn) 繪制整個(gè)正六邊形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();}繪制出來(lái)的效果是一樣的。但是方法以及變了。
然后來(lái)畫第二行,第二行起點(diǎn)的path應(yīng)該在這里
坐標(biāo)是: 2a , height/2 ?這里的偏移量不變。
首先將畫path的方法提取出來(lái)(as快捷鍵ctrl + alt + m)
//根據(jù)左上角一點(diǎn) 繪制整個(gè)正六邊形private void getPath(float height, float x, float y) {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();}然后再給個(gè)循環(huán),來(lái)繪制第二行的六邊形 for(int i = 0;i<2;i++){float offset = mLength * 3 * i ;float x = mLength*2 + offset;float y = height/2;getPath(height,x,y);}canvas.drawPath(mPath,mPaint);得到如下的效果。現(xiàn)在ondraw的全部代碼如下:
@Overrideprotected void onDraw(Canvas canvas) {mPaint.setColor(Color.parseColor("#FFBB33"));//正六邊形的高float height = (float) (Math.sqrt(3)*mLength);for(int i = 0 ; i < 3;i++) {//橫坐標(biāo)偏移量float offset = mLength * 3 * i ;//左上角的xfloat x = mLength/2 + offset;float y = 0;getPath(height, x, y);}canvas.drawPath(mPath,mPaint);mPath.reset();mPaint.setColor(Color.parseColor("#AA66CC"));for(int i = 0;i<2;i++){float offset = mLength * 3 * i ;float x = mLength*2 + offset;float y = height/2;getPath(height,x,y);}canvas.drawPath(mPath,mPaint);}接下來(lái)對(duì)每行的個(gè)數(shù)進(jìn)行一下控制。 //每行的個(gè)數(shù)private int mColumnsCount = 3;//行數(shù)private int mLineCount = 3;
對(duì)應(yīng)的循環(huán)也改變,最外面套一個(gè)大循環(huán),來(lái)控制多行繪制 for (int j = 0; j < mLineCount; j++) {if(j%2 == 0) 繪制奇數(shù)行 else 繪制偶數(shù)行}現(xiàn)在整個(gè)ondraw如下。
@Overrideprotected void onDraw(Canvas canvas) {//正六邊形的高float height = (float) (Math.sqrt(3) * mLength);for (int j = 0; j < mLineCount; j++) {if (j % 2 == 0) {mPaint.setColor(Color.parseColor("#FFBB33"));for (int i = 0; i < mColumnsCount; i++) {//橫坐標(biāo)偏移量float offset = mLength * 3 * i;//左上角的xfloat x = mLength / 2 + offset;float y = j * height / 2;getPath(height, x, y);}canvas.drawPath(mPath, mPaint);mPath.reset();} else {mPaint.setColor(Color.parseColor("#AA66CC"));for (int i = 0; i < mColumnsCount; i++) {float offset = mLength * 3 * i;float x = mLength * 2 + offset;float y = (height / 2) * j;getPath(height, x, y);}canvas.drawPath(mPath, mPaint);mPath.reset();}}}
好像顏色一樣就不好看了。。那我們來(lái)動(dòng)態(tài)改變一下顏色..
添加一個(gè)屬性list來(lái)存放color
private ArrayList<Integer> mColorList; mColorList = new ArrayList<>();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"));嗯。。看起來(lái)像一點(diǎn)樣子了。。。 給中間加點(diǎn)文字吧。。
先給每個(gè)蜂窩編號(hào)
按上面的循環(huán) ? j為行數(shù) ?i為列數(shù) ?
研究規(guī)律發(fā)現(xiàn) ? 編號(hào)等于 j*3 + i?
我們有六邊形左上角的坐標(biāo)xy 可以輕易的計(jì)算出中心坐標(biāo)
這些都有了。開一個(gè)list存放中間的文字:
//存放文字的listprivate ArrayList<String> mTextList ;繪制文字: 這里要注意他和path的繪制順序,如果path后繪制則會(huì)覆蓋掉文字 float txtLength = mTextPaint.measureText(mTextList.get(txtId));canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);
下面是全部的ondraw
@Overrideprotected void onDraw(Canvas canvas) {//正六邊形的高float height = (float) (Math.sqrt(3) * mLength);for (int j = 0; j < mLineCount; j++) {mPaint.setColor(mColorList.get(j));if (j % 2 == 0) {// mPaint.setColor(Color.parseColor("#FFBB33"));for (int i = 0; i < mColumnsCount; i++) {int txtId = j*3 +i;//橫坐標(biāo)偏移量float offset = mLength * 3 * i;//左上角的xfloat x = mLength / 2 + offset;float y = j * height / 2;mPath.reset();getPath(height, x, y);canvas.drawPath(mPath, mPaint);float txtLength = 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 (int i = 0; i < mColumnsCount; i++) {int txtId = j*3 +i;float offset = mLength * 3 * i;float x = mLength * 2 + offset;float y = (height / 2) * j;mPath.reset();getPath(height, x, y);canvas.drawPath(mPath, mPaint);float txtLength = mTextPaint.measureText(mTextList.get(txtId));canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);}}}}現(xiàn)在的效果圖如下:
好,那現(xiàn)在讓他靈活一點(diǎn)。添加各種set方法,比如行數(shù)啊 列數(shù)啊 ?邊長(zhǎng)啊 文字內(nèi)容啊 顏色啊之類的。
/*** 設(shè)置列數(shù)* @param mColumnsCount*/public void setColumnsCount(int mColumnsCount) {this.mColumnsCount = mColumnsCount;invalidate();}/*** 設(shè)置行數(shù)* @param mLineCount*/public void setLineCount(int mLineCount) {this.mLineCount = mLineCount;invalidate();}/*** 設(shè)置文本數(shù)據(jù)*/public void setTextList(ArrayList<String> textList) {mTextList.clear();mTextList.addAll(textList);invalidate();}/*** 設(shè)置顏色數(shù)據(jù)* @param colorList*/public void setColorList(ArrayList<Integer> colorList) {mColorList.clear();mColorList.addAll(colorList);invalidate();}然后 你有沒有忘記測(cè)量呢? 只要把最外面的矩形大小給他就行 @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = 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);}這下使用wrap_content 來(lái)看看view的大小:
嗯。。測(cè)量也對(duì)著。。。 ? 這里我只實(shí)現(xiàn)了wrap_content ?大家可以以及擴(kuò)展 讓他支持EXACTLY
這樣 一個(gè)蜂窩煤的view 就完成了。。。但是好像沒鳥用的樣子。。因?yàn)闆]有交互的話。。圖片完全可以代替。所以這次就先遺留一個(gè)問題,事件的處理。其實(shí)邏輯也不是很復(fù)雜,就是判斷觸摸點(diǎn) 是否在Path內(nèi),如果action_up的時(shí)候在,分開編號(hào),按照編號(hào)進(jìn)行回調(diào)即可,這個(gè)問題,準(zhǔn)備下篇博客解決,請(qǐng)大家繼續(xù)關(guān)注我的博客 蟹蟹!。
本項(xiàng)目地址:點(diǎn)擊打開鏈接
如果你覺得我寫的還不錯(cuò),請(qǐng)點(diǎn)擊一下頂,繼續(xù)關(guān)注我。謝謝!!
轉(zhuǎn)載于:https://www.cnblogs.com/muyuge/p/6333541.html
總結(jié)
以上是生活随笔為你收集整理的手把手带你画一个漂亮蜂窝view Android自定义view的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 判断字符串是不存在json中
- 下一篇: Struts2国际化文件乱码解决