手把手帶你畫一個漂亮蜂窩view Android自訂view

來源:互聯網
上載者:User

標籤:

上一篇做了一個水波紋view  不知道大家有沒有動手試試呢點擊開啟連結


這個效果做起來好像沒什麼意義,如果不加監聽回調 圖片就能直接替代。寫這篇部落格的目的是鍛煉一下思維能力,以更好的面多各種自訂view需求。


轉載請註明出處:http://blog.csdn.net/wingichoy/article/details/50554058


本文是和代碼同步寫的。也就是說在寫文章的時候才敲的代碼。這樣會顯得文章有些許混亂。但是我想這樣記錄下來,一個自訂view的真正的製作過程,是一點一點,一步步跟著思路的改變,完善的。不可能一下子就做出一個完整的view。。技術也是這樣,不可能一步登天。都是一步一步的積累。


另外,每一篇部落格都是建立在之前部落格的基礎知識上的,如果你剛接觸自訂view。可以來說說自訂view簡單學習的方式這裡看我以前的文章。記錄了我學習自訂view的過程,而且前幾篇部落格或多或少犯了一些錯誤。這裡我並不想改正博文中的錯誤,因為些錯誤是大家經常會犯的,後來的部落格都有指出這些錯誤,以及不再犯,這是一個學習的過程。所以我想把錯誤的經曆記錄下來。等成為高手 回頭看看當年的自己是多麼菜。。也會有成就感。。



老規矩如下:


首先畫一個六邊形,畫之前來計算一下六邊形的相關知識:


假設一個正六邊形的邊長為a  ,因為每個角都是120°  所以可得高為根號三a  ,。


有了這些資訊我們就可以繪製一個六邊形出來,如下:


 float height = (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; 

 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();        }

發現效果如下


這不對啊,很奇怪啊。。 底下空出來的一個三角形放不下我們的第二行啊。。

那麼怎麼辦呢。。 加大offset!  加大多少呢。。 應該多增加一個邊長。。這樣就正好留空了。 來試試



現在來準備畫第二行....

發現我們之前path的座標都是相對寫死的。。 所以要回過頭改一下,改成給定一個起點,就可以繪製出一個六邊形,經過計算,得出


這裡a代表邊長。

改完之後的代碼是:

 float height = (float) (Math.sqrt(3)*mLength);        for(int i = 0 ; i < 3;i++) {            //橫座標位移量            int offset = mLength * 3 * i ;            //左上方的x            int x = mLength/2 + offset;            int y = 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)

 //根據左上方一點 繪製整個正六邊形    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();    }
然後再給個迴圈,來繪製第二行的六邊形

        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);
得到如下的效果。


現在ondraw的全部代碼如下:

  @Override    protected void onDraw(Canvas canvas) {        mPaint.setColor(Color.parseColor("#FFBB33"));        //正六邊形的高        float height = (float) (Math.sqrt(3)*mLength);        for(int i = 0 ; i < 3;i++) {            //橫座標位移量            float offset = mLength * 3 * i ;            //左上方的x            float 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);    }

接下來對每行的個數進行一下控制。

  //每行的個數    private int mColumnsCount = 3;    //行數    private int mLineCount = 3;

對應的迴圈也改變,最外面套一個大迴圈,來控制多行繪製

 for (int j = 0; j < mLineCount; j++) {         if(j%2 == 0)  繪製奇數行 else 繪製偶數行}
現在整個ondraw如下。
@Override    protected 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++) {                    //橫座標位移量                    float offset = mLength * 3 * i;                    //左上方的x                    float 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();            }        }    }


好像顏色一樣就不好看了。。那我們來動態改變一下顏色..

添加一個屬性list來存放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"));


在迴圈中,取出顏色值

 for (int j = 0; j < mLineCount; j++) {            mPaint.setColor(mColorList.get(j));


效果如下:


嗯。。看起來像一點樣子了。。。 給中間加點文字吧。。

先給每個蜂窩編號



按上面的迴圈   j為行數  i為列數  

研究規律發現   編號等於 j*3 + i 

我們有六邊形左上方的座標xy 可以輕易的計算出中心座標







這些都有了。開一個list存放中間的文字:

    //存放文字的list    private ArrayList<String> mTextList ;


在初始化的時候給添加點資料

  mTextList = new ArrayList<>();        for(int i =0;i<mLineCount*mColumnsCount;i++){            mTextList.add("wing "+i);        }        mTextPaint = new Paint();        mTextPaint.setTextSize(20);


繪製文字: 這裡要注意他和path的繪製順序,如果path後繪製則會覆蓋掉文字

 float txtLength = mTextPaint.measureText(mTextList.get(txtId));                    canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);


下面是全部的ondraw

  @Override    protected 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;                    //橫座標位移量                    float offset = mLength * 3 * i;                    //左上方的x                    float 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);                }            }        }    }

現在的如下:

好,那現在讓他靈活一點。添加各種set方法,比如行數啊 列數啊  邊長啊 文字內容啊 顏色啊之類的。

  /**     * 設定列數     * @param mColumnsCount     */    public void setColumnsCount(int mColumnsCount) {        this.mColumnsCount = mColumnsCount;        invalidate();    }    /**     * 設定行數     * @param mLineCount     */    public void setLineCount(int mLineCount) {        this.mLineCount = mLineCount;        invalidate();    }    /**     * 設定文本資料     */    public void setTextList(ArrayList<String> textList) {        mTextList.clear();        mTextList.addAll(textList);        invalidate();    }    /**     * 設定顏色資料     * @param colorList     */    public void setColorList(ArrayList<Integer> colorList) {        mColorList.clear();        mColorList.addAll(colorList);        invalidate();    }
然後 你有沒有忘記測量呢? 只要把最外面的矩形大小給他就行

    @Override    protected 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 來看看view的大小:


嗯。。測量也對著。。。   這裡我只實現了wrap_content  大家可以以及擴充 讓他支援EXACTLY




這樣 一個蜂窩煤的view 就完成了。。。但是好像沒鳥用的樣子。。因為沒有互動的話。。圖片完全可以代替。所以這次就先遺留一個問題,事件的處理。其實邏輯也不是很複雜,就是判斷觸摸點 是否在Path內,如果action_up的時候在,分開編號,按照編號進行回調即可,這個問題,準備下篇部落格解決,請大家繼續關注我的部落格 蟹蟹!。


本項目地址:點擊開啟連結


如果你覺得我寫的還不錯,請點擊一下頂,繼續關注我。謝謝!!

手把手帶你畫一個漂亮蜂窩view Android自訂view

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.