Android自定義實(shí)現(xiàn)六邊形按鈕繪制
今天逛酷安的時(shí)候,發(fā)現(xiàn)酷安的設(shè)置按鈕(截圖的右上角),是一個(gè)六邊形 + 中心圓的圖標(biāo),所以又是一個(gè)自定義View練習(xí)對(duì)象了。畫圓很簡(jiǎn)單,知道半徑即可,而重點(diǎn)就在畫出六邊形。

最終效果:

原理:
1、中心畫一個(gè)小圓
2、再畫一個(gè)六邊形(難點(diǎn))
怎樣才能畫六邊形,?只要我們計(jì)算出6個(gè)角的坐標(biāo)點(diǎn),用Path連接即可。至于怎么計(jì)算,就要使用三角函數(shù)。我們這樣分析:
在六邊形中心畫一個(gè)內(nèi)切圓,6個(gè)角都在圓上。360被六邊形的6個(gè)角平分,每個(gè)角就為60度,而每個(gè)角的2條腰的長(zhǎng)都是圓的半徑。如下圖所示:

至于三角函數(shù),可能我們會(huì)忘記,我們對(duì)著這張圖解圖來(lái)回憶一下。

只要我們計(jì)算出中心角的角度,用三角函數(shù)中的cos()就可以計(jì)算出點(diǎn)的x坐標(biāo),sin()就可以計(jì)算出y坐標(biāo)(注意這個(gè)2個(gè)方法傳入的角度需要轉(zhuǎn)為弧度)。重點(diǎn)計(jì)算代碼在drawPolygon()方法。
完整代碼:
自定義屬性
Java代碼
public class PolygonSettingView extends View {/*** View默認(rèn)最小寬度*/private static final int DEFAULT_MIN_WIDTH = 100;/*** 畫筆*/private Paint mPaint;/*** 控件寬*/private int mViewWidth;/*** 控件高*/private int mViewHeight;/*** 多邊形的邊數(shù)*/private int mNum;/*** 最小的多邊形的半徑*/private float mRadius;/*** 360度對(duì)應(yīng)的弧度(為什么2π就是360度?弧度的定義:弧長(zhǎng) / 半徑,一個(gè)圓的周長(zhǎng)是2πr,如果是一個(gè)360度的圓,它的弧長(zhǎng)就是2πr,如果這個(gè)圓的半徑r長(zhǎng)度為1,那么它的弧度就是,2πr / r = 2π)*/private final double mPiDouble = 2 * Math.PI;/*** 多邊形中心角的角度(每個(gè)多邊形的內(nèi)角和為360度,一個(gè)多邊形2個(gè)相鄰角頂點(diǎn)和中心的連線所組成的角為中心角* 中心角的角度都是一樣的,所以360度除以多邊形的邊數(shù),就是一個(gè)中心角的角度),這里注意,因?yàn)楹罄m(xù)要用到Math類的三角函數(shù)* Math類的sin和cos需要傳入的角度值是弧度制,所以這里的中心角的角度,也是弧度制的弧度*/private float mCenterAngle;/*** 顏色*/private int mColor;/*** 中心小圓的半徑*/private float mSmallCircleRadius;/*** 線寬*/private float mLineWidth;public PolygonSettingView(Context context) {this(context, null);}public PolygonSettingView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public PolygonSettingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs, defStyleAttr);}private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {initAttr(context, attrs, defStyleAttr);//取消硬件加速setLayerType(LAYER_TYPE_SOFTWARE, null);//畫筆mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setStyle(Paint.Style.STROKE);mPaint.setColor(mColor);mPaint.setStrokeWidth(mLineWidth);}private void initAttr(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {//默認(rèn)邊數(shù)和最小邊數(shù)int defaultNum = 6;int minNum = 3;int defaultColor = Color.argb(255, 0, 0, 0);int defaultLineWidth = dip2px(context, 1.5f);if (attrs != null) {TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PolygonSettingView, defStyleAttr, 0);mColor = array.getColor(R.styleable.PolygonSettingView_psv_color, defaultColor);int num = array.getInt(R.styleable.PolygonSettingView_psv_num, defaultNum);mNum = num <= minNum ? minNum : num;mLineWidth = array.getDimension(R.styleable.PolygonSettingView_psv_line_width, defaultLineWidth);array.recycle();} else {mColor = defaultColor;mNum = defaultNum;}//計(jì)算中心角弧度mCenterAngle = (float) (mPiDouble / mNum);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mViewWidth = w;mViewHeight = h;//計(jì)算最小的多邊形的半徑mRadius = (Math.min(mViewWidth, mViewHeight) / 2f) * 0.95f;//計(jì)算中心小圓的半徑mSmallCircleRadius = (Math.min(mViewWidth, mViewHeight) / 2f) * 0.3f;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//將畫布中心移動(dòng)到中心點(diǎn)canvas.translate(mViewWidth / 2, mViewHeight / 2);//畫小圓drawSmallCircle(canvas);//畫多邊形drawPolygon(canvas);}/*** 畫小圓*/private void drawSmallCircle(Canvas canvas) {canvas.drawCircle(0, 0, mSmallCircleRadius, mPaint);}/*** 畫多邊形*/private void drawPolygon(Canvas canvas) {//多邊形邊角頂點(diǎn)的x坐標(biāo)float pointX;//多邊形邊角頂點(diǎn)的y坐標(biāo)float pointY;//總的圓的半徑,就是全部多邊形的半徑之和Path path = new Path();//畫前先重置路徑path.reset();for (int i = 1; i <= mNum; i++) {//cos三角函數(shù),中心角的鄰邊 / 斜邊,斜邊的值剛好就是半徑,cos值乘以斜邊,就能求出鄰邊,而這個(gè)鄰邊的長(zhǎng)度,就是點(diǎn)的x坐標(biāo)pointX = (float) (Math.cos(i * mCenterAngle) * mRadius);//sin三角函數(shù),中心角的對(duì)邊 / 斜邊,斜邊的值剛好就是半徑,sin值乘以斜邊,就能求出對(duì)邊,而這個(gè)對(duì)邊的長(zhǎng)度,就是點(diǎn)的y坐標(biāo)pointY = (float) (Math.sin(i * mCenterAngle) * mRadius);//如果是一個(gè)點(diǎn),則移動(dòng)到這個(gè)點(diǎn),作為起點(diǎn)if (i == 1) {path.moveTo(pointX, pointY);} else {//其他的點(diǎn),就可以連線了path.lineTo(pointX, pointY);}}path.close();canvas.drawPath(path, mPaint);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(handleMeasure(widthMeasureSpec), handleMeasure(heightMeasureSpec));}/*** 處理MeasureSpec*/private int handleMeasure(int measureSpec) {int result = DEFAULT_MIN_WIDTH;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY) {result = specSize;} else {//處理wrap_content的情況if (specMode == MeasureSpec.AT_MOST) {result = Math.min(result, specSize);}}return result;}public static int dip2px(Context context, float dipValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}}
簡(jiǎn)單使用
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="10dp"
app:psv_color="@android:color/black"
app:psv_line_width="1.5dp"
app:psv_num="6" />到這里就結(jié)束了。
評(píng)論
圖片
表情
