bertZuo 2018-09-29
目录介绍
好消息
1.Paint画笔介绍
1.1 图形绘制
* setARGB(int a,int r,int g,int b); 设置绘制的颜色,a代表透明度,r,g,b代表颜色值。 * setAlpha(int a); 设置绘制图形的透明度。 * setColor(int color); 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。 * setAntiAlias(boolean aa); 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。 * setDither(boolean dither); 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 * setFilterBitmap(boolean filter); 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于dither和xfermode的设置 * setMaskFilter(MaskFilter maskfilter); 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等 * setColorFilter(ColorFilter colorfilter); 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果 * setPathEffect(PathEffect effect); 设置绘制路径的效果,如点画线等 * setShader(Shader shader); 设置图像效果,使用Shader可以绘制出各种渐变效果 * setShadowLayer(float radius ,float dx,float dy,int color); 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色 * setStyle(Paint.Style style); 设置画笔的样式,为FILL,FILL_AND_STROKE,或STROKE * setStrokeCap(Paint.Cap cap); 当画笔样式为STROKE或FILL_AND_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE * setSrokeJoin(Paint.Join join); 设置绘制时各图形的结合方式,如平滑效果等 * setStrokeWidth(float width); 当画笔样式为STROKE或FILL_AND_STROKE时,设置笔刷的粗细度 * setXfermode(Xfermode xfermode); 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
1.2 文本绘制
* setFakeBoldText(boolean fakeBoldText); 模拟实现粗体文字,设置在小字体上效果会非常差 * setSubpixelText(boolean subpixelText); 设置该项为true,将有助于文本在LCD屏幕上的显示效果 * setTextAlign(Paint.Align align); 设置绘制文字的对齐方向 * setTextScaleX(float scaleX); 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果 * setTextSize(float textSize); 设置绘制文字的字号大小 * setTextSkewX(float skewX); 设置斜体文字,skewX为倾斜弧度 * setTypeface(Typeface typeface); 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等 * setUnderlineText(boolean underlineText); 设置带有下划线的文字效果 * setStrikeThruText(boolean strikeThruText); 设置带有删除线的效果
2.Canvas画布介绍
2.1 设置属性
* Canvas(Bitmap bitmap): 以bitmap对象创建一个画布,则将内容都绘制在bitmap上,因此bitmap不得为null。 * Canvas(GL gl): 在绘制3D效果时使用,与OpenGL相关。 * isOpaque(boolean isOpaque):检测是否支持透明。 * setViewport(int left, int top, int right, int bottom, int clipflag): 设置画布中显示窗口。 * drawColor(int color): 设置Canvas的背景颜色。 * setBitmap(Bitmap mBitmap): 设置具体画布,画的内容,保存为一个Bitmap。 * clipRect(float left, float top, float right, float bottom): 设置显示区域,即设置裁剪区。 * translate(float x, float y): 平移画布。 * rotate(float degree, float px, float py): 旋转画布 。 * skew(float sx, float sy): 设置偏移量。 * save(): 将Canvas当前状态保存在堆栈,save之后可以调用Canvas的平移、旋转、错切、剪裁等操作。 * restore(): 恢复为之前堆栈保存的Canvas状态,防止save后对Canvas执行的操作对后续的绘制有影响。restore和save要配对使用,restore可以比save少,但不能比save多,否则会引发error。save和restore之间,往往夹杂的是对Canvas的特殊操作。 * save(int num):将Canvas当前状态保存在堆栈,并予以编号int * restoreToCount(int num):恢复为之前堆栈保存的编号为int的Canvas状态 * concat(Matrix matrix):画布关联矩阵,画出来的内容按矩阵改变,而不是画布改变。 * Drawable.draw(Canvas canvas):将Drawable画到Canvas中 注:这种方式画Drawable怎么设置透明度呢?((BitmapDrawable)Drawable).getPaint().setAlpha(mBgAlpha);
2.2 画图【重点】
* canvas.drawPaint(Paint paint) 将画笔设置的颜色和透明度铺满画布 * drawRect(RectF rect, Paint paint) 绘制矩形,参数一为RectF一个区域 * drawRect(float left, float top, float right, float bottom, Paint paint) 绘制矩形,left:矩形left的x坐标,top:矩形top的y坐标,right:矩形right的x坐标,bottom:矩形bottom的y坐标 * drawRoundRect(RectF rect, float rx, float ry, Paint paint) 绘制圆角矩形, rx:x方向的圆角半径,ry:y方向的圆角半径 * drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) * drawPath(Path path, Paint paint) 绘制一个路径,参数一为Path路径对象 * drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) 贴图,参数一就是我们常规的Bitmap对象,参数二是源区域(这里是bitmap),参数三是目标区域(应该在canvas的位置和大小),参数四是Paint画刷对象,因为用到了缩放和拉伸的可能,当原始Rect不等于目标Rect时性能将会有大幅损失。 * drawBitmap (Bitmap bitmap, float left, float top, Paint paint) * drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) 画线,参数一起始点的x轴位置,参数二起始点的y轴位置,参数三终点的x轴水平位置,参数四y轴垂直位置,最后一个参数为Paint 画刷对象。 * drawPoint(float x, float y, Paint paint) 画点,参数一水平x轴,参数二垂直y轴,第三个参数为Paint对象。 * drawText(String text, float x, floaty, Paint paint) 渲染文本,Canvas类除了上面的还可以描绘文字,参数一是String类型的文本,参数二文字左侧到x轴距离,参数三文字BaseLine到y轴距离,参数四是Paint对象。 * drawOval(RectF oval, Paint paint) 绘制椭圆,参数一是扫描区域,参数二为paint对象 * drawOval(float left, float top, float right, float bottom, Paint paint) * drawCircle(float cx, float cy, float radius,Paint paint) 绘制圆,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象; * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 画弧,参数一是RectF对象,指定圆弧的外轮廓矩形区域,参数二是起始角(度)在电弧的开始,参数三扫描角(度)开始顺时针测量的,参数四是如果这是真的话,包括椭圆中心的电弧,并关闭它,如果它是假这将是一个弧线,参数五是Paint对象;
2.3 Canvas对象的获取方式
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
Canvas canvas = new Canvas();2.4 Canvas的作用
2.5 Canvas绘制圆和椭圆
private Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(200,200,100 , paint);
}2.6 Canvas绘制矩形、圆角矩形

private Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(100, 100, 200, 200, paint);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawRoundRect(400, 100, 600, 300, 30, 30, paint);
}
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20);
canvas.drawRect(100, 400, 300, 600, paint);
}2.7 Canvas绘制文字

private Paint paint = new Paint();
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setTextSize(100);
canvas.drawText("潇湘剑雨", 100, 100, paint);
}2.8 Canvas绘制弧形、封闭弧形

private Paint paint = new Paint();
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rel = new RectF(50, 50, 150, 150);
//实心圆弧
canvas.drawArc(rel, 0, 135, false, paint);
//实心圆弧 将圆心包含在内
RectF rel2 = new RectF(50, 200, 150, 300);
canvas.drawArc(rel2, 0, 135, true, paint);
//设置空心Style
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20);
RectF rel3 = new RectF(50, 350, 150, 450);
canvas.drawArc(rel3, 0, 270, false, paint);
RectF rel4 = new RectF(50, 250, 150, 600);
canvas.drawArc(rel4, 0, 270, true, paint);
}2.9 Canvas绘制Path路径

private Paint paint = new Paint();
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path angle = new Path();
angle.moveTo(250, 0);
angle.lineTo(0, 500);
angle.lineTo(100, 300);
angle.lineTo(200, 350);
angle.lineTo(500, 500);
angle.close();
canvas.drawPath(angle, paint);
}3.Matrix变换矩阵介绍【Canvas位置转换】
3.1 translate平移
3.2 rorate旋转

private Paint mPaint = new Paint();
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLUE);
mPaint.setColor(Color.RED);
canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
canvas.save();
mPaint.setColor(Color.GREEN);
canvas.rotate(45,400,400);
canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
canvas.restore();
}/**
* Preconcat the current matrix with the specified rotation.
* @param degrees The amount to rotate, in degrees
*/
public native void rotate(float degrees);
/**
* Preconcat the current matrix with the specified rotation.
* @param degrees The amount to rotate, in degrees
* @param px The x-coord for the pivot point (unchanged by the rotation)
* @param py The y-coord for the pivot point (unchanged by the rotation)
*/
public final void rotate(float degrees, float px, float py) {
translate(px, py);
rotate(degrees);
translate(-px, -py);
}3.3 scale缩放

private Paint mPaint = new Paint();
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.YELLOW);
mPaint.setColor(Color.RED);
canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
// 保存画布状态
canvas.save();
canvas.scale(0.5f, 0.5f);
mPaint.setColor(Color.GREEN);
canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
// 画布状态回滚
canvas.restore();
canvas.scale(0.5f, 0.5f, 400, 400);
mPaint.setColor(Color.BLUE);
canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
}/**
* Preconcat the current matrix with the specified scale.
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
*/
public native void scale(float sx, float sy);
/**
* Preconcat the current matrix with the specified scale.
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
* @param px The x-coord for the pivot point (unchanged by the scale)
* @param py The y-coord for the pivot point (unchanged by the scale)
*/
public final void scale(float sx, float sy, float px, float py) {
translate(px, py);
scale(sx, sy);
translate(-px, -py);
}3.4 skew扭曲
4.RectF介绍
4.1 Rect简单属性
public int left; public int top; public int right; public int bottom;
public Rect(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public Rect(Rect r) {
if (r == null) {
left = top = right = bottom = 0;
} else {
left = r.left;
top = r.top;
right = r.right;
bottom = r.bottom;
}
}
4.2 Rect父类的实现
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Rect r = (Rect) o;
return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
}
@Override
public int hashCode() {
int result = left;
result = 31 * result + top;
result = 31 * result + right;
result = 31 * result + bottom;
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(32);
sb.append("Rect("); sb.append(left); sb.append(", ");
sb.append(top); sb.append(" - "); sb.append(right);
sb.append(", "); sb.append(bottom); sb.append(")");
return sb.toString();
}4.3 Rect常用的一些方法
//文章开头说的公式在这里得到了应验
public final int width() {
return right - left;
}public final int height() {
return bottom - top;
}//因为left是最左侧,right比left还小不就不成形了么?宽高同是如此
public final boolean isEmpty() {
return left >= right || top >= bottom;
}public void setEmpty() {
left = right = top = bottom = 0;
}public void set(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}5.关于使用到这几个属性的自定义View
5.1 自定义轮播图圆点
/**
* <pre>
* @author yangchong
* blog : https://github.com/yangchong211
* time : 2016/5/18
* desc : 红点自定义控件
* revise: 建议设置红点宽高一样,否则是椭圆
* </pre>
*/
public class DotView extends View {
private boolean isInit = false;
private boolean isSelected = false;
private float mViewHeight;
private float mViewWidth;
private float mRadius;
private Paint mPaintBg = new Paint();
private int mBgUnselectedColor = Color.parseColor("#1A000000");
private int mBgSelectedColor = Color.parseColor("#FDE26E");
private static final float mArcWidth = 2.0f;
public DotView(Context context) {
super(context);
}
public DotView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DotView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isInit) {
isInit = true;
mViewHeight = getHeight();
mViewWidth = getWidth();
if (mViewHeight >= mViewWidth) {
mRadius = mViewWidth / 2.f;
} else {
mRadius = mViewHeight / 2.f;
}
}
//是否选中
if (isSelected){
drawSelectedDot(canvas);
} else{
drawUnSelectedDot(canvas);
}
}
/**
* 绘制选中指示器红点
* @param canvas canvas
*/
private void drawSelectedDot(Canvas canvas) {
//设置paint相关属性
mPaintBg.setAntiAlias(true);
mPaintBg.setColor(mBgSelectedColor);
mPaintBg.setStyle(Style.FILL);
//绘制圆
canvas.drawCircle(mViewWidth / 2.f, mViewHeight / 2.f, mRadius - 8.f, mPaintBg);
mPaintBg.setStyle(Style.STROKE);
float offset = 1.f + mArcWidth;
RectF oval = new RectF(mViewWidth / 2.f - mRadius + offset, mViewHeight / 2.f - mRadius + offset,
mViewWidth / 2.f + mRadius - offset, mViewHeight / 2.f + mRadius - offset);
//绘制指定的弧线,该弧线将被缩放以适应指定的椭圆形。
canvas.drawArc(oval, 0.f, 360.f, false, mPaintBg);
}
/**
* 绘制未选中指示器红点
* @param canvas canvas
*/
private void drawUnSelectedDot(Canvas canvas) {
mPaintBg.setAntiAlias(true);
mPaintBg.setColor(mBgUnselectedColor);
mPaintBg.setStyle(Style.FILL);
canvas.drawCircle(mViewWidth / 2.f, mViewHeight / 2.f, mRadius - 8.f, mPaintBg);
}
/**
* 设置是否选中
* @param isSelected isSelected
*/
public void setIsSelected(boolean isSelected) {
this.isSelected = isSelected;
//使整个视图无效。如果视图是可见的,则{@link#onDraw(android.Graphics.Canvas)}将在将来的某个时候被调用。
//调用该方法,会进行重新绘制,也就是调用onDraw方法
this.invalidate();
}
}5.2 自定义圆环百分比进度条
public class ARoundImageView extends AppCompatImageView {
/*
* Paint:画笔
* Canvas:画布
* Matrix:变换矩阵
*
* 业务需求:可以设置圆角,可以设置圆形,如果是圆角则必须设置半径,默认圆角半径为10dp
*/
/**
* 圆形模式
*/
private static final int MODE_CIRCLE = 1;
/**
* 普通模式
*/
private static final int MODE_NONE = 0;
/**
* 圆角模式
*/
private static final int MODE_ROUND = 2;
/**
* 圆角半径
*/
private int currRound = dp2px(10);
/**
* 画笔
*/
private Paint mPaint;
/**
* 默认是普通模式
*/
private int currMode = 0;
public ARoundImageView(Context context) {
this(context,null);
}
public ARoundImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ARoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyledAttrs(context, attrs, defStyleAttr);
initViews();
}
private void obtainStyledAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ARoundImageView, defStyleAttr, 0);
currMode = a.hasValue(R.styleable.ARoundImageView_type) ? a.getInt(R.styleable.ARoundImageView_type, MODE_NONE) : MODE_NONE;
currRound = a.hasValue(R.styleable.ARoundImageView_radius) ? a.getDimensionPixelSize(R.styleable.ARoundImageView_radius, currRound) : currRound;
a.recycle();
}
private void initViews() {
//ANTI_ALIAS_FLAG 用于绘制时抗锯齿
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
}
/**
* 当模式为圆形模式的时候,我们强制让宽高一致
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (currMode == MODE_CIRCLE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int result = Math.min(getMeasuredHeight(), getMeasuredWidth());
// 此方法必须由{@link#onMeasure(int,int)}调用,以存储已测量的宽度和测量的高度。
// 如果不这样做,将在测量时触发异常。
setMeasuredDimension(result, result);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
//获取ImageView图片资源
Drawable mDrawable = getDrawable();
//获取Matrix对象
Matrix mDrawMatrix = getImageMatrix();
if (mDrawable == null) {
return;
}
if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) {
return;
}
if (mDrawMatrix == null && getPaddingTop() == 0 && getPaddingLeft() == 0) {
mDrawable.draw(canvas);
} else {
final int saveCount = canvas.getSaveCount();
canvas.save();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (getCropToPadding()) {
final int scrollX = getScrollX();
final int scrollY = getScrollY();
canvas.clipRect(scrollX + getPaddingLeft(), scrollY + getPaddingTop(),
scrollX + getRight() - getLeft() - getPaddingRight(),
scrollY + getBottom() - getTop() - getPaddingBottom());
}
}
canvas.translate(getPaddingLeft(), getPaddingTop());
switch (currMode){
case MODE_CIRCLE:
Bitmap bitmap1 = drawable2Bitmap(mDrawable);
mPaint.setShader(new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint);
break;
case MODE_ROUND:
Bitmap bitmap2 = drawable2Bitmap(mDrawable);
mPaint.setShader(new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawRoundRect(new RectF(getPaddingLeft(), getPaddingTop(),
getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()),
currRound, currRound, mPaint);
break;
case MODE_NONE:
default:
if (mDrawMatrix != null) {
canvas.concat(mDrawMatrix);
}
mDrawable.draw(canvas);
break;
}
canvas.restoreToCount(saveCount);
}
}
/**
* drawable转换成bitmap
*/
private Bitmap drawable2Bitmap(Drawable drawable) {
if (drawable == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
//根据传递的scaleType获取matrix对象,设置给bitmap
Matrix matrix = getImageMatrix();
if (matrix != null) {
canvas.concat(matrix);
}
drawable.draw(canvas);
return bitmap;
}
private int dp2px(float value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
value, getResources().getDisplayMetrics());
}
}