android 使用canvas绘制正多边行
我们先重温初中生都知道的几个概念
正多边行每个圆心角都是相等的,也就是360/n(n是指多少边行)
二个相邻的点构成的线是相等的
见图:
然后通过Path,把相邻的二个点连接起来就形成了一个Path,绘制到画布(canvas)就ok,
代码如下:
package com.multilateral.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import java.util.HashMap; import java.util.Map; /** * Created by zhouguizhi on 2017/9/25. */ public class CustomMultilateralView extends View { private Paint paint; private int number = 8;//8边形 private float STROKEWIDTH = 4; private float STROKEWIDTH_LINE = 2; private boolean isDrawCircle = true;//是否绘制外圆 private boolean isJoinLine = true; private Map<Float,Float> points ; private float centerX; private float centerY; public CustomMultilateralView(Context context) { this(context,null); } public CustomMultilateralView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public CustomMultilateralView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomMultilateralView); number = typedArray.getInteger(R.styleable.CustomMultilateralView_number, 4); isDrawCircle = typedArray.getBoolean(R.styleable.CustomMultilateralView_isDrawCircle,isDrawCircle); isJoinLine = typedArray.getBoolean(R.styleable.CustomMultilateralView_isjoinLine,isJoinLine); typedArray.recycle(); init(); points = new HashMap<>(); } private void init() { paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(STROKEWIDTH); paint.setColor(Color.RED); paint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { if(number < 3) { return; } drawCircle(canvas); drawPath(canvas); drawJoinLines(canvas); } private void drawJoinLines(Canvas canvas) { if(null==canvas){ return; } paint.setStrokeWidth(STROKEWIDTH_LINE); for (Map.Entry<Float, Float> entry: points.entrySet()) { canvas.drawLine(centerX,centerY,entry.getKey(),entry.getValue(),paint); } } private void drawPath(Canvas canvas) { if(null==canvas){ return; } paint.setStrokeWidth(STROKEWIDTH); float radius = getHeight() / 2-2; centerX = getMeasuredHeight()/2; centerY = getMeasuredHeight()/2; Path path = new Path(); for (int i = 0; i <=number; i++) { float alpha = Double.valueOf(((2f / number) * i) * Math.PI).floatValue();//2π/n是求出每一个圆心角的角度 float nextX = centerX + Double.valueOf(radius * Math.cos(alpha)).floatValue(); float nextY = centerY + Double.valueOf(radius * Math.sin(alpha)).floatValue(); points.put(nextX,nextY); if (i == 0) { path.moveTo(nextX, nextY); } else { path.lineTo(nextX, nextY); } } canvas.drawPath(path, paint); } private void drawCircle(Canvas canvas) { if(null==canvas){ return; } if(isDrawCircle){ canvas.drawCircle(getMeasuredHeight()/2,getMeasuredHeight()/2,getMeasuredHeight()/2-STROKEWIDTH/2,paint); } } }attrs.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CustomMultilateralView"> <attr name="number" format="integer" /> <attr name="isDrawCircle" format="boolean"></attr> <attr name="isjoinLine" format="boolean"></attr> </declare-styleable> </resources>布局文件:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:zhou="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <com.multilateral.view.CustomMultilateralView android:layout_width="300dp" android:layout_height="300dp" android:layout_centerInParent="true" zhou:number="12" zhou:isDrawCircle="false" zhou:isjoinLine="true" /> </RelativeLayout>效果图: