Paint.Style.STROKE 只绘制图形轮廓(描边)
Paint.Style.FILL 只绘制图形内容
Paint.Style.FILL_AND_STROKE 既绘制轮廓也绘制内容
Paint.Join.BEVEL 斜边
Paint.Join.MITER 锐角
Paint.Join.ROUND 圆角
圆的
public class CircleView extends View {
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private float mAnimatorValue;
private Path mDst;
private float mLength;
public CircleView(Context context) {
super(context);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
mPathMeasure = new PathMeasure();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(6);
mPaint.setTextSize(60);
// mPaint.setStrokeCap(Paint.Cap.BUTT);
//圆形的时候 有明显的圆形 开头/结尾
mPaint.setStrokeCap(Paint.Cap.ROUND);
// mPaint.setStrokeCap(Paint.Cap.SQUARE);
// mPaint.setStrokeJoin(Paint.Join.BEVEL);
// mPaint.setStrokeJoin(Paint.Join.MITER);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPath = new Path();
//200 200 这个点 就是这个圆形 中心坐标 这个坐标是相对于 View在XML 里的左上角的点为0 0
// mPath.addCircle(200, 200, 100, Path.Direction.CW); // 顺时针转
mPath.addCircle(600, 600, 300, Path.Direction.CW); //逆时针转
// forceClosed Path最终是否需要闭合,如果为True的话,
// 则不管关联的Path是否是闭合的,都会被闭合。
mPathMeasure.setPath(mPath, false);
mLength = mPathMeasure.getLength();
mDst = new Path();
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.start();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
// 硬件加速的BUG 加上这个会在左上角留下一个黑点
// mDst.lineTo(0, 0);
float stop = mLength * mAnimatorValue;
float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));
mPathMeasure.getSegment(start, stop, mDst, true);
// mPathMeasure.getSegment(0, stop, mDst, true);
canvas.drawPath(mDst, mPaint);
//Path.Direction.CCW 时 文字在内环
canvas.drawTextOnPath("超级无敌长的一段文字.", mDst, 0, -20, mPaint);
}
}
三角形的
public class PathPainterEffect extends View implements View.OnClickListener {
private Paint mPaint;
private Path mPath;
private PathMeasure mPathMeasure;
private PathEffect mEffect;
private float fraction = 0;
private ValueAnimator mAnimator;
public PathPainterEffect(Context context) {
super(context);
}
public PathPainterEffect(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mPath.reset();
mPath.moveTo(100, 100);
mPath.lineTo(100, 500);
mPath.lineTo(400, 300);
mPath.close(); //坐标闭合 这里如果是forceClosed 为true 不起效果 俺也不知道
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPathMeasure = new PathMeasure(mPath, false);
final float length = mPathMeasure.getLength();
mAnimator = ValueAnimator.ofFloat(1, 0);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.setDuration(2000);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
fraction = (float) valueAnimator.getAnimatedValue();
mEffect = new DashPathEffect(new float[]{length, length}, fraction * length);
mPaint.setPathEffect(mEffect);
invalidate();
}
});
setOnClickListener(this);
}
public PathPainterEffect(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
}
@Override
public void onClick(View view) {
mAnimator.start();
}
}
对勾View
public class MyView_Duihao extends View {
private Paint mPaint;
private Path mPath;
private int[] loc;
public MyView_Duihao(Context context) {
this(context, null);
}
public MyView_Duihao(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView_Duihao(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
loc = new int[2];
getLocationInWindow(loc);
mPaint = new Paint();
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
mPath = new Path();
mPath.moveTo(width * 0.2f, height * 0.5f);
mPath.quadTo(width / 2f, height, width * 0.8f, height * 0.1f);
canvas.drawPath(mPath, mPaint);
}
}
让对号动起来
public class MyView_Duihao extends View implements View.OnClickListener {
private Paint mPaint;
private Path mPath;
private int[] loc;
private ValueAnimator mAnimator;
//可以主动传进来
private int width;
private int height;
public MyView_Duihao(Context context) {
this(context, null);
}
public MyView_Duihao(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView_Duihao(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
loc = new int[2];
getLocationInWindow(loc);
mPaint = new Paint();
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
mPath = new Path();
width = dip2px(context, 100);
height = dip2px(context, 100);
mPath.moveTo(width * 0.2f, height * 0.5f);
mPath.quadTo(width / 2f, height, width * 0.8f, height * 0.1f);
PathMeasure mPathMeasure = new PathMeasure(mPath, false);
final float length = mPathMeasure.getLength();
mAnimator = ValueAnimator.ofFloat(1, 0);
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.setDuration(2000);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = (float) animation.getAnimatedValue();
DashPathEffect mEffect = new DashPathEffect(new float[]{length, length}, fraction * length);
mPaint.setPathEffect(mEffect);
invalidate();
}
});
setOnClickListener(this);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
}
@Override
public void onClick(View v) {
mAnimator.start();
}
/**
* 根据手机的分辨率从 dip 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
这里有一个问题,因为不能在onDraw里边进行 宽高的获取,所以我们可以直接拿xml 里边的宽高
文字逐渐缩短 ,无法接着扩展了....当然可以自定义样式来写一个,,,下一个
// 圆的直径
final int height = v.getHeight();
int width = v.getWidth();
final RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
ValueAnimator valueAnimator = ValueAnimator.ofInt(width, height);
ValueAnimator valueAnimator2 = ValueAnimator.ofInt(0, (width - height) / 2);
valueAnimator.setDuration(duration);
valueAnimator2.setDuration(duration);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
layoutParams.width = animatedValue;
v.setLayoutParams(layoutParams);
}
});
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
v.setTranslationX(animatedValue);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(valueAnimator)
.with(valueAnimator2);
animatorSet.start();
如果实在相对布局中,给View设置固定的位置 那么久只需要第一个Animator 就可以实现了
如果是线性布局,那么他会自动贴边.同样的固定一个位置比如 父布局中
android:gravity="center_horizontal"
使用一个动画Animator 就可以了
public class AnimationButton extends View {
/**
* view的宽度
*/
private int width;
/**
* view的高度
*/
private int height;
/**
* 圆角半径
*/
private int circleAngle;
/**
* 默认两圆圆心之间的距离=需要移动的距离
*/
private int default_two_circle_distance;
/**
* 两圆圆心之间的距离
*/
private int two_circle_distance;
/**
* 背景颜色
*/
private int bg_color = 0xffbc7d53;
/**
* 按钮文字字符串
*/
private String buttonStringBefore = "点我登录";
private String buttonStringAfter = "完事了";
/**
* 是否开始绘制 完成文字
*/
private boolean isOver = false;
/**
* 动画执行时间
*/
private int duration = 1000;
/**
* view向上移动距离
*/
private int move_distance = 300;
/**
* 圆角矩形画笔
*/
private Paint paint;
/**
* 文字画笔
*/
private Paint textPaint;
/**
* 文字绘制所在矩形
*/
private Rect textRect = new Rect();
/**
* 动画集
*/
private AnimatorSet animatorSet = new AnimatorSet();
/**
* 矩形到圆角矩形过度的动画
*/
private ValueAnimator animator_rect_to_angle;
/**
* 矩形到正方形过度的动画
*/
private ValueAnimator animator_rect_to_square;
/**
* 根据view的大小设置成矩形
*/
private RectF rectf = new RectF();
/**
* 路径--用来获取对勾的路径
*/
private Path path = new Path();
/**
* 对路径处理实现绘制动画效果
*/
private PathEffect effect;
/**
* 点击事件及动画事件2完成回调
*/
private AnimationButtonListener animationButtonListener;
public void setAnimationButtonListener(AnimationButtonListener listener) {
animationButtonListener = listener;
}
public AnimationButton(Context context) {
this(context, null);
}
public AnimationButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AnimationButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (animationButtonListener != null) {
animationButtonListener.onClickListener();
}
}
});
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (animationButtonListener != null) {
animationButtonListener.animationFinish();
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
/**
* 初始化所有动画
*/
private void initAnimation() {
set_rect_to_angle_animation();
set_rect_to_circle_animation();
animatorSet
.play(animator_rect_to_square)
.after(animator_rect_to_angle);
}
/**
* 设置矩形过度到圆角矩形的动画
*/
private void set_rect_to_angle_animation() {
animator_rect_to_angle = ValueAnimator.ofInt(0, height / 2);
animator_rect_to_angle.setDuration(duration);
animator_rect_to_angle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
circleAngle = (int) animation.getAnimatedValue();
invalidate();
}
});
}
/**
* 设置圆角矩形过度到圆的动画
*/
private void set_rect_to_circle_animation() {
animator_rect_to_square = ValueAnimator.ofInt(0, default_two_circle_distance);
animator_rect_to_square.setDuration(duration);
animator_rect_to_square.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
two_circle_distance = (int) animation.getAnimatedValue();
if (default_two_circle_distance != 0) {
// int alpha = 255 - (two_circle_distance * 255) / default_two_circle_distance;
// textPaint.setAlpha(alpha);
}
if (two_circle_distance == default_two_circle_distance) {
isOver = true;
}
invalidate();
}
});
}
private void initPaint() {
paint = new Paint();
paint.setStrokeWidth(4);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setColor(bg_color);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(60);
textPaint.setColor(Color.WHITE);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setAntiAlias(true);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
default_two_circle_distance = (w - h) / 2;
initAnimation();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
draw_oval_to_circle(canvas);
if (isOver) {
isOver = false;
drawText(canvas, buttonStringAfter);
}else{
drawText(canvas, buttonStringBefore);
}
}
/**
* 绘制长方形变成圆形
*
* @param canvas 画布
*/
private void draw_oval_to_circle(Canvas canvas) {
rectf.left = two_circle_distance;
rectf.top = 0;
rectf.right = width - two_circle_distance;
rectf.bottom = height;
//画圆角矩形
canvas.drawRoundRect(rectf, circleAngle, circleAngle, paint);
}
/**
* 绘制文字
*
* @param canvas 画布
*/
private void drawText(Canvas canvas, String string) {
textRect.left = 0;
textRect.top = 0;
textRect.right = width;
textRect.bottom = height;
Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
//文字绘制到整个布局的中心位置
canvas.drawText(string, textRect.centerX(), baseline, textPaint);
}
/**
* 启动动画
*/
public void start() {
animatorSet.start();
}
/**
* 动画还原
*/
public void reset() {
circleAngle = 0;
two_circle_distance = 0;
default_two_circle_distance = (width - height) / 2;
textPaint.setAlpha(255);
setTranslationY(getTranslationY() + move_distance);
invalidate();
}
/**
* 借口回调
*/
public interface AnimationButtonListener {
/**
* 按钮点击事件
*/
void onClickListener();
/**
* 动画完成回调
*/
void animationFinish();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
mWidth = Math.min(mWidth, mHeight);
} else {
mWidth = dp2px(getContext(), 50);
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = Math.min(mWidth, mHeight);
} else {
mHeight = dp2px(getContext(), 50);
}
mWidth = mHeight = Math.min(mWidth, mHeight);
setMeasuredDimension(mWidth, mHeight);
}
画虚线:
1.Shape
layerType 是关闭硬件加速
2.自定义View
关闭硬件加速
public class MyView extends View {
private Paint mPaint;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.STROKE); // 边框
mPaint.setStrokeWidth(10);//宽度
mPaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setLayerType(LAYER_TYPE_SOFTWARE, null);
int centerY = getHeight() / 2;
canvas.drawLine(0, centerY, getWidth(), centerY, mPaint);
}
}
3.不关硬件加速
public class MyView extends View {
private Paint mPaint;
private Path mPath;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.STROKE); // 边框
mPaint.setStrokeWidth(10);//宽度
mPaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0));
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
int centerY = getHeight() / 2;
mPath.moveTo(0,centerY);
mPath.lineTo(getWidth(), centerY);
canvas.drawPath(mPath, mPaint);
}
}
4.自定义虚线样式
public class MyView extends View {
private Paint mPaint;
private Path mPath;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.STROKE); // 边框
mPaint.setStrokeWidth(10);//宽度
Path path = new Path();
path.addCircle(0, 0, 5, Path.Direction.CW);
mPaint.setPathEffect(new PathDashPathEffect(path, 15, 0, PathDashPathEffect.Style.ROTATE));
mPath = new Path();
}
// 其它方法还是不变
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 前四个参数没啥好讲的,就是起点和终点而已。
// color数组的意思是从透明 -> 黑 -> 黑 -> 透明。
// float数组与color数组对应:
// 0 -> 0.3 (透明 -> 黑)
// 0.3 - 0.7 (黑 -> 黑,即不变色)
// 0.7 -> 1 (黑 -> 透明)
mPaint.setShader(new LinearGradient(0, 0, getWidth(), 0,
new int[] {Color.TRANSPARENT, Color.BLACK, Color.BLACK, Color.TRANSPARENT},
new float[] {0, 0.3f, 0.7f, 1f}, Shader.TileMode.CLAMP));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
int centerY = getHeight() / 2;
mPath.moveTo(0,centerY);
mPath.lineTo(getWidth(), centerY);
canvas.drawPath(mPath, mPaint);
}
}
在这里,学到了一种View 设置渐变色的方法,可以通过LinearGradient()初始化的四个点来设置渐变的方向
画弧:
public class MyView extends View {
private Paint mPaint;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.STROKE); // 边框
mPaint.setStrokeWidth(10);//宽度
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF mRectF = new RectF(100, 200, 700, 600); //这个矩形的 左上 右下俩个点 (100,200),(700,600)
canvas.drawRect(mRectF, mPaint);
mPaint.setColor(Color.RED);
canvas.drawArc(mRectF, 180, 270, false, mPaint);
}
}
这里主要是这个方法
canvas.drawArc(mRectF, 180, 270, false, mPaint);
改变一下参数看看
canvas.drawArc(mRectF, 180, 270, true, mPaint);
Path mPath = new Path();
mPath.moveTo(10, 10);
RectF mRectF = new RectF(100, 200, 700, 600); //这个矩形的 左上 右下俩个点 (100,200),(700,600)
canvas.drawRect(mRectF, mPaint);
mPaint.setColor(Color.RED);
canvas.drawArc(mRectF, 0, 90, true, mPaint);
mPaint.setColor(Color.GREEN);
mPath.addArc(mRectF, 180, 90);
canvas.drawPath(mPath, mPaint);
改为ArcTo
mPath.arcTo(mRectF, 180, 90);
mPath.arcTo(mRectF, 180, 90,true);
在arcTo 的方法里有一个参数
Region
public class MyView extends View {
private Paint mPaint;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.STROKE); // 边框
mPaint.setStrokeWidth(10);//宽度
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect mRect = new Rect(100, 100, 500, 300);
Region mRegion = new Region(mRect);
drawRegion(canvas, mRegion, mPaint);
}
private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
RegionIterator iterator = new RegionIterator(mRegion);
Rect rectF = new Rect();
while (iterator.next(rectF)) {
canvas.drawRect(rectF, mPaint);
}
}
}
类似普通的矩形,但是既然要通过Region来包装,那么这里一定是有不同寻常的Api
它可以用来画俩个区域重叠的地方
public class MyView extends View {
private Paint mPaint;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.FILL); // 边框
mPaint.setStrokeWidth(10);//宽度
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path mPath = new Path();
mPath.addOval(new RectF(100, 100, 500, 500), Path.Direction.CW);
Region mRegion = new Region();
Rect mRect = new Rect(100, 100, 500, 200);
mRegion.setPath(mPath, new Region(mRect));
drawRegion(canvas, mRegion, mPaint);
}
private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
RegionIterator iterator = new RegionIterator(mRegion);
Rect rectF = new Rect();
while (iterator.next(rectF)) {
canvas.drawRect(rectF, mPaint);
}
}
}
union函数
区域相交 合并矩形
Region region = new Region(10, 10, 510, 410);
region.union(new Rect(10,10,310,610));
drawRegion(canvas, region, mPaint);
op方法
public class MyView extends View {
private Paint mPaint;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//设置抗锯齿
mPaint.setColor(Color.BLACK);//设置画笔颜色
mPaint.setDither(true);// 防止抖动
mPaint.setStyle(Paint.Style.STROKE); // 边框
mPaint.setStrokeWidth(10);//宽度
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rect1 = new Rect(100, 100, 400, 200);
Rect rect2 = new Rect(200, 0, 300, 300);
Region region1 = new Region(rect1);
Region region2 = new Region(rect2);
Region region = new Region();
// region.op(region1, region2, Region.Op.DIFFERENCE);
// region.op(region1, region2, Region.Op.INTERSECT);
// region.op(region1, region2, Region.Op.REPLACE);
// region.op(region1, region2, Region.Op.UNION);
// region.op(region1, region2, Region.Op.XOR);
region.op(region1, region2, Region.Op.REVERSE_DIFFERENCE);
canvas.drawRect(rect1, mPaint);
canvas.drawRect(rect2, mPaint);
mPaint.setStyle(Paint.Style.FILL);
drawRegion(canvas, region, mPaint);
}
private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
RegionIterator iterator = new RegionIterator(mRegion);
Rect rectF = new Rect();
while (iterator.next(rectF)) {
canvas.drawRect(rectF, mPaint);
}
}
}
canvas.save/restore
当我们对canvas(画布)进行操作后就需要对画布状态进行保存(save),恢复(restore)
举个栗子
canvas.drawCircle(100, 100, 50, mPaint);
canvas.translate(200, 200);
canvas.drawCircle(100, 100, 50, mPaint);
默认的中心点是:0,0 所有100,100的圆在左上角,当我们使用translate之后画布换了位置,中心点到了200,200,所以100,100画在了右下角
canvas.drawCircle(100, 100, 50, mPaint);
canvas.save();
canvas.translate(200, 200);
canvas.restore();
mPaint.setColor(Color.RED);
canvas.drawCircle(110, 110, 50, mPaint);
可以看到这样画布恢复了,中心点又回去了
小栗子:
canvas.drawCircle(500, 500, 400, mPaint);
mPaint.setStyle(Paint.Style.FILL); // 实心
for (int i = 0; i < 7; i++) {
canvas.save();
canvas.rotate(60 * i, 500, 500);
canvas.drawLine(500, 500, 500, 0, mPaint);
canvas.restore();
}
// 看看最终的中心点在哪
canvas.drawPoint(10, 10, mPaint);
这个有个问题,每次打开App 然后退到后台不杀死再打开就会变成Fill 类型的
这个问题找到了原因了就是每次界面可见时,就会调用自定义View 的OnDraw ,所以