自定义view学习笔记一:五角星绘制
刚开始学习自定义view,记录一下学习过程。
参考了网络上的一些博文,自定义view需要关注最多的就是3个方法:onMeasure(), onLayout(),onDraw(),而其中最关键的就是onDraw()方法了。而自定义view中我们需要做的就是在canvas上面通过paint来画出我们想要的图形,下面是画五角星的代码。
package com.leen.android.customviewtest;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import static java.lang.Math.PI;
public class AngleView extends View {
private static String TAG = "AngleView";
private int defaultWidth = 300;
private int defaultHeight = 300; //view的默认宽高
private int mCenterX;
private int mCenterY; //view的中心点
private int mBackgroudColor;
private int mPaintColor;
private int mRotation; //五角星旋转角度
private Paint mPaint;
private Path mPath;
public AngleView(Context context) {
this(context, null);
}
public AngleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AngleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mBackgroudColor = Color.RED;
mPaintColor = Color.YELLOW;
mRotation = 0;
if(mPaint == null)
mPaint = new Paint();
if(mPath == null)
mPath = new Path();
//setLayerType(View.LAYER_TYPE_SOFTWARE, null);
//mPaint.setAntiAlias(true);
}
private int getMySize(int measureSpec, int defaultSize) {
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
Log.d(TAG, "defaultSize=" + defaultSize + ", mode=" + mode + ", size=" + size);
switch (mode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
return defaultSize;
case MeasureSpec.EXACTLY:
return size;
default:
return defaultSize;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMySize(widthMeasureSpec, defaultWidth);
int height = getMySize(heightMeasureSpec, defaultHeight);
setMeasuredDimension(width, height);
mCenterX = getMeasuredWidth() / 2;
mCenterY = getMeasuredHeight() / 2;
Log.d(TAG, "mCenterX=" + mCenterX + ", mCenterY=" + mCenterY);
int r = getMeasuredWidth() / 3; //五角星外接圆半径
float angle = 72f; //五个角对应的角度 360/5
double rad = 2 * PI / 360; //1度对应的弧度
//五角星五个角顶点坐标算法:
//x = r * cos(n * angle * rad)
//y = r * sin(n * angle * rad)
float a[] = {(float) (Math.cos(0 * angle * rad) * r), (float) (Math.sin(0 * angle * rad) * r)};
float b[] = {(float) (Math.cos(1 * angle * rad) * r), (float) (-Math.sin(1 * angle * rad) * r)};
float c[] = {(float) (Math.cos(2 * angle * rad) * r), (float) (-Math.sin(2 * angle * rad) * r)};
float d[] = {(float) (Math.cos(3 * angle * rad) * r), (float) (-Math.sin(3 * angle * rad) * r)};
float e[] = {(float) (Math.cos(4 * angle * rad) * r), (float) (-Math.sin(4 * angle * rad) * r)};
mPath.moveTo(a[0], a[1]);
mPath.lineTo(c[0], c[1]);
mPath.lineTo(e[0], e[1]);
mPath.lineTo(b[0], b[1]);
mPath.lineTo(d[0], d[1]);
mPath.close();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG, "onDraw()");
mPaint.setColor(mPaintColor);
canvas.translate(mCenterX, mCenterY); //将画布原点移动到view中心
canvas.drawColor(mBackgroudColor);
canvas.rotate(mRotation); //旋转画布,顺时针为正,逆时针为负
canvas.drawPath(mPath, mPaint);
}
public void setColor(int backgroudColor, int paintColor) {
mBackgroudColor = backgroudColor;
mPaintColor = paintColor;
invalidate();
}
public void setRotate(int rotate) {
mRotation = rotate;
invalidate();
}
}
代码算比较简单了,我的做法是确定好五角星的五个顶点坐标,然后连成线,再填充。这个过程中也遇到了一些问题,比较关键的就是五个顶点坐标的算法,还有原点坐标默认是左上角,需要做个位移。
效果图如下: