Hand-held to show you a pretty honeycomb view Android custom view

Source: Internet
Author: User
Tags addall drawtext

Hand-held to show you a pretty honeycomb view Android custom view

This effect does not seem to make any sense, and can be directly replaced without listening for callback images. The purpose of writing this blog is to train your thinking skills to better meet various custom view requirements.

This article is written in sync with the code. That is, the code that is typed only when writing an article. This may seem a little confusing. However, I want to record that the real creation process of a custom view is 1.1 points, and the idea is changed and improved step by step. It is impossible to make a complete view at once .. The same is true for technology. Is a step-by-step accumulation.

In addition, each blog is based on the basic knowledge of the previous blog, if you are new to custom view. For more information, see my previous articles here. I recorded the process of learning custom views, and the previous blogs made more or less mistakes. Here I don't want to correct the mistakes in the blog, because some mistakes are often made by people. Later blogs have pointed out these mistakes and won't make them any more. This is a learning process. So I want to record the wrong experiences. When you become a master, let's look back at how delicious you were .. It also has a sense of accomplishment ..

The old rules are as follows:

First draw a hexagonal image and calculate the knowledge about the hexagonal format before drawing it:

Assume that the side length of a positive hexagonal is a, because each angle is 120 °, so the height can be 3, ,.

With this information, we can draw a hexagonal structure, as shown below:

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

Rendering effect:

 

Then it is translated according to an offset, and multiple rectangles can be drawn in a loop.

 

Here, offset is the offset. If it is next to it, it should be the width of a hexagonal offset. The width can be a/2 + a/2, that is, 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();        }

The results are as follows:

 

This is not correct. It's strange .. A triangle that is empty below cannot fit our second line ..

So what should we do .. Increase offset! How much does it increase .. Add an extra side length .. In this way, leave it empty. To try

Now I want to draw the second line ....

We found that the coordinates of our previous paths are relatively dead .. So let's look at it and change it to a given starting point. Then we can draw a hexagonal structure.

Here, a indicates the side length.

The code after modification is:

Float height = (float) (Math. sqrt (3) * mLength); for (int I = 0; I <3; I ++) {// horizontal offset int offset = mLength * 3 * I; // x int x = mLength/2 + offset in the upper left corner; int y = 0; // draw the entire hexagonal mPath according to the point in the upper left corner. 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 ();}

The effects are the same. But the method and change.

Then draw the second line. The path from the second line should be here.

Coordinates: 2a, height/2. The offset remains unchanged.

First, extract the path method (as shortcut: ctrl + alt + m)

// Draw the entire hexagonal 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 ();}
Then, let's create a loop to draw the hexagonal Line 2.
        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);
The following results are displayed.


Now all ondraw code is as follows:

@ Override protected void onDraw (Canvas canvas) {mPaint. setColor (Color. parseColor ("# FFBB33"); // high float height = (float) (Math. sqrt (3) * mLength); for (int I = 0; I <3; I ++) {// horizontal offset float offset = mLength * 3 * I; // x float x = mLength/2 + offset in the upper left corner; 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 );}

Next, we will control the number of rows.
// The number of rows private int mColumnsCount = 3; // The number of rows private int mLineCount = 3;

The corresponding loop also changes, and the outermost side sets a large loop to control multi-row rendering.
For (int j = 0; j <mLineCount; j ++) {if (j % 2 = 0) draw an odd row else draw an even row}
Now the entire ondraw is as follows.
@ Override protected void onDraw (Canvas canvas) {// high 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 ++) {// horizontal offset float offset = mLength * 3 * I; // x float x = mLength/2 + offset in the upper left corner; 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 ();}}}

It looks pretty bad like the color .. Let's change the color dynamically ..

Add an attribute list to store color.

    private ArrayList
 
   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"));
In the loop, retrieve the color value
 for (int j = 0; j < mLineCount; j++) {            mPaint.setColor(mColorList.get(j));
The effect is as follows:

Well .. It looks like a bit... Add text in the middle ..

Give each cell number first

In the preceding cycle, j is the number of rows. I is the number of columns.

The study found that the number is equal to j * 3 + I.

We have the coordinate xy in the upper left corner of the hexagonal to easily calculate the Center Coordinate.

These are all available. Open a list to store intermediate text:

// List private ArrayList for storing text
 
  
MTextList;
 
Add vertex data during initialization
MTextList = new ArrayList <> (); for (int I = 0; I
 
  
Draw text: Pay attention to the order in which he and path are drawn. If the path is drawn later, the text will be overwritten.
  
 float txtLength = mTextPaint.measureText(mTextList.get(txtId));                    canvas.drawText(mTextList.get(txtId),x+mLength/2-txtLength/2,y+height/2+5, mTextPaint);

Below is all ondraw

@ Override protected void onDraw (Canvas canvas) {// high 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; // horizontal coordinate offset float offset = mLength * 3 * I; // x float x = mLength/2 + offset in the upper left corner; 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 );}}}}

The following are the examples:

Well, now let him be more flexible. Add various set methods, such as the number of rows, number of columns, length of sides, text content, color, and so on.

/*** Set the number of columns ** @ param mColumnsCount */public void setColumnsCount (int mColumnsCount) {this. mColumnsCount = mColumnsCount; invalidate ();}/*** set the number of rows * @ param mLineCount */public void setLineCount (int mLineCount) {this. mLineCount = mLineCount; invalidate ();}/*** set text data */public void setTextList (ArrayList
   
    
TextList) {mTextList. clear (); mTextList. addAll (textList); invalidate () ;}/ *** set color data * @ param colorList */public void setColorList (ArrayList
    
     
ColorList) {mColorList. clear (); mColorList. addAll (colorList); invalidate ();}
    
   
Have you forgotten the measurement? Just give him the size of the outermost rectangle.
    @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);    }

The following uses wrap_content to check the view Size:

Well .. The measurement is also facing... Here I only implement wrap_content. You can and extend it to support EXACTLY.


Such a view of honeycomb coal is complete... But it seems useless .. Because there is no interaction .. Images can be replaced. So this time, we will leave a problem behind and handle the event. In fact, the logic is not very complex, that is, to determine whether the touch point is in the Path. If action_up is used, separate the numbers and perform callback based on the numbers. This problem is solved in the next blog, please keep an eye on my blog !.

Project address: Click to open the link

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.