自定义View之 onDraw()(三)
上两篇已经介绍了自定义View的onMeasure和onLayout方法,那么接下来我们继续深究自定义view的 onDraw(Canvas canvas) ,在探究 onDraw方法之前,我们必须先深入了解两个类Paint和Canvas 。
第一:认识Paint
实为画笔,大家自行搜索看看就是,soeasy!!!
第二:认识Canvas
Canvas类简单理解就是表示一块画布,可以在上面画我们想画的东西
Canvas中的方法很多,Canvas可以绘制的对象有:
弧线(arcs) canvas.
填充颜色(argb和color)
Bitmap
圆(circle和oval)
点(point)
线(line)
矩形(Rect)
图片(Picture)
圆角矩形 (RoundRect)
文本(text)
顶点(Vertices)
路径(path)
canvas.save():把当前的绘制的图像保存起来,让后续的操作相当于是在一个新的图层上的操作。
canvas.restore(); 把当前画布返回(调整)到上一个save()状态之前
canvas.translate(dx, dy); //把当前画布的原点移到(dx,dy),后面的操作都以(dx,dy)作为参照点,默认原点为(0,0)
canvas.scale(x,y);扩大。x为水平方向的放大倍数,y为竖直方向的放大倍数
canvas.rotate(angel):旋转.angle指旋转的角度,顺时针旋转。
canvas.transform():切变。所谓切变,其实就是把图像的顶部或底部推到一边。
canvas.saveLayer(bounds, paint, saveFlags);
第三:Canvas 的复杂使用,模拟支付宝芝麻信用分动画效果。
上两篇已经介绍了自定义View的onMeasure和onLayout方法,那么接下来我们继续深究自定义view的 onDraw(Canvas canvas) ,在探究 onDraw方法之前,我们必须先深入了解两个类Paint和Canvas 。
第一:认识Paint
实为画笔,大家自行搜索看看就是,soeasy!!!
第二:认识Canvas
Canvas类简单理解就是表示一块画布,可以在上面画我们想画的东西
Canvas中的方法很多,Canvas可以绘制的对象有:
弧线(arcs) canvas.
填充颜色(argb和color)
Bitmap
圆(circle和oval)
点(point)
线(line)
矩形(Rect)
图片(Picture)
圆角矩形 (RoundRect)
文本(text)
顶点(Vertices)
路径(path)
canvas.save():把当前的绘制的图像保存起来,让后续的操作相当于是在一个新的图层上的操作。
canvas.restore(); 把当前画布返回(调整)到上一个save()状态之前
canvas.translate(dx, dy); //把当前画布的原点移到(dx,dy),后面的操作都以(dx,dy)作为参照点,默认原点为(0,0)
canvas.scale(x,y);扩大。x为水平方向的放大倍数,y为竖直方向的放大倍数
canvas.rotate(angel):旋转.angle指旋转的角度,顺时针旋转。
canvas.transform():切变。所谓切变,其实就是把图像的顶部或底部推到一边。
canvas.saveLayer(bounds, paint, saveFlags);
第三:Canvas 的复杂使用,模拟支付宝芝麻信用分动画效果。
package com.suowei.appsuowei.myview;
import com.example.appsuowei.R;
import com.suowei.appsuowei.util.DensityUtil;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.text.format.Time;
import android.util.AttributeSet;
import android.view.View;
public class RoundIndicatorView extends View{
private int maxNum;
private int startAngle;
private int sweepAngle;
private int sweepInWidth;
private int sweepOutWidth;
private Paint paint,paint2,paint3,paint4;
private int mWidth,mHeight;
private int radius;
private Context context;
private int currentNum;
public int getCurrentNum() {
return currentNum;
}
public void setCurrentNum(int currentNum) {
this.currentNum = currentNum;
invalidate();
System.out.println("currentNum>>>>>>>"+currentNum);
}
private String[] textStrings={"菜鸟","初级","良好","优秀","大师"};
public RoundIndicatorView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context=context;
initAttr(attrs, context);
initPaint();
}
public RoundIndicatorView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
initAttr(attrs, context);
initPaint();
}
public RoundIndicatorView(Context context) {
super(context);
this.context=context;
}
private void initAttr(AttributeSet attrs,Context context){
TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.RoundIndicatorView);
maxNum=typedArray.getInt(R.styleable.RoundIndicatorView_maxNum, 500);
startAngle=typedArray.getInt(R.styleable.RoundIndicatorView_startAngle, 160);
sweepAngle=typedArray.getInt(R.styleable.RoundIndicatorView_sweepAngle, 220);
System.out.println("startAngle....."+startAngle+"sweepAngle>>>>>"+sweepAngle);
sweepInWidth=DensityUtil.sp2px(context, 8);
sweepOutWidth=DensityUtil.sp2px(context, 3);
System.out.println("sweepInWidth....."+sweepInWidth+"sweepOutWidth>>>>>"+sweepOutWidth);
typedArray.recycle();
}
private void initPaint(){
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(context.getResources().getColor(R.color.white));
paint2=new Paint(Paint.ANTI_ALIAS_FLAG);
paint3=new Paint(Paint.ANTI_ALIAS_FLAG);
paint4=new Paint(Paint.ANTI_ALIAS_FLAG);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
radius=getMeasuredWidth()/4;
canvas.save();
canvas.translate(mWidth/2, (mWidth)/2);
drawRound(canvas);//画内外圆弧
drawScale(canvas);
drawIndicator(canvas);
drawCenterText(canvas);
canvas.restore();
}
private void drawRound(Canvas canvas){
//内圆
canvas.save();
paint.setAlpha(0x40);
paint.setStrokeWidth(sweepInWidth);
RectF rectF=new RectF(-radius, -radius, radius, radius);
canvas.drawArc(rectF, startAngle, sweepAngle, false, paint);
//外圆
paint.setStrokeWidth(sweepOutWidth);
int w=DensityUtil.dip2px(context, 10);
RectF rectF2=new RectF(-radius-w, -radius-w, radius+w, radius+w);
canvas.drawArc(rectF2, startAngle, sweepAngle, false, paint);
canvas.restore();
}
private void drawScale(Canvas canvas){
canvas.save();
float angle=(float)sweepAngle/30;
canvas.rotate(-270+startAngle);//将画布正上方移动到起始位置
for(int i=0;i<=30;i++){
if(i%6==0){
paint.setStrokeWidth(DensityUtil.dip2px(context, 2));
paint.setAlpha(0x70);
canvas.drawLine(0, -radius-sweepInWidth/2, 0, -radius+sweepInWidth/2+DensityUtil.dip2px(context, 1), paint);
DrawText(canvas, i*maxNum/30+"", paint);
}else {
paint.setStrokeWidth(DensityUtil.dip2px(context, 1));
paint.setAlpha(0x50);
canvas.drawLine(0, -radius-sweepInWidth/2, 0, -radius+sweepInWidth/2, paint);
}
if(i==3 || i==9 || i==15 || i==21 || i==27){
paint.setStrokeWidth(DensityUtil.dip2px(context, 2));
paint.setAlpha(0x50);
DrawText(canvas, textStrings[(i-3)/6], paint);
}
canvas.rotate(angle);
}
canvas.restore();
}
private void DrawText(Canvas canvas,String textStrings,Paint paint){
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(DensityUtil.dip2px(context, 8));
float width=paint.measureText(textStrings);
canvas.drawText(textStrings, -width/2, -radius+DensityUtil.dip2px(context, 15), paint);
paint.setStyle(Paint.Style.STROKE);
}
private void drawIndicator(Canvas canvas){
canvas.save();
int sweep;
if(currentNum<=maxNum){
sweep=(int) ((float)currentNum/(float)maxNum*sweepAngle);
}else {
sweep=sweepAngle;
}
//画扫过后外圆的颜色
paint2.setStyle(Paint.Style.STROKE);
paint2.setStrokeWidth(sweepOutWidth);
Shader shader=new SweepGradient(0, 0, 0,context.getResources().getColor(R.color.white));
paint2.setShader(shader);
int w=DensityUtil.dip2px(context, 10);
RectF rectF=new RectF(-radius-w, -radius-w, radius+w, radius+w);
System.out.println("sweep>>>>>>>>>>>>>>"+sweep);
if(sweep!=0){
canvas.drawArc(rectF, startAngle, sweep, false, paint2);
}
float x=(float)((radius+DensityUtil.dip2px(context, 10))*Math.cos(Math.toRadians(startAngle+sweep)));
float y=(float)((radius+DensityUtil.dip2px(context, 10))*Math.sin(Math.toRadians(startAngle+sweep)));
paint3.setStyle(Paint.Style.FILL);
paint3.setColor(0xffffffff);
paint3.setMaskFilter(new BlurMaskFilter(DensityUtil.dip2px(context, 3), BlurMaskFilter.Blur.SOLID));
canvas.drawCircle(x, y, DensityUtil.dip2px(context, 3), paint3);
canvas.restore();
}
private void drawCenterText(Canvas canvas){
canvas.save();
paint4.setStyle(Paint.Style.FILL);
paint4.setTextSize(radius/2);
paint4.setColor(context.getResources().getColor(R.color.white));
canvas.drawText(currentNum+"", -paint4.measureText(currentNum+"")/2, 0, paint4);
paint4.setTextSize(radius/4);
String content="视频";
String appendString=null;
if(currentNum<maxNum*1/5){
appendString=textStrings[0]+content;
}else if (currentNum>=maxNum*1/5 && currentNum<maxNum*2/5) {
appendString=textStrings[1]+content;
}else if (currentNum>=maxNum*2/5 && currentNum<maxNum*3/5) {
appendString=textStrings[2]+content;
}else if (currentNum>=maxNum*3/5 && currentNum<maxNum*4/5) {
appendString=textStrings[3]+content;
}else if (currentNum>=maxNum*4/5) {
appendString=textStrings[4]+content;
}
Rect rect=new Rect();
paint4.getTextBounds(appendString, 0, appendString.length(), rect);
canvas.drawText(appendString, -rect.width()/2, rect.height()+10, paint4);
// Rect timeRect=new Rect();
// String timeString=getSystemTime();
// paint4.setTextSize(radius/8);
// paint4.getTextBounds(timeString, 0, timeString.length(), timeRect);
// canvas.drawText(timeString, -timeRect.width()/2, timeRect.height()+40, paint4);
canvas.restore();
}
public void setCurrentNumAnim(int num){
//根据进度差计算动画时间
float duration=(float)Math.abs(num-currentNum)/maxNum*1500+500;
System.out.println("duration>>>>>>>"+duration);
ObjectAnimator animator=ObjectAnimator.ofInt(this, "currentNum",num);
animator.setDuration((long)Math.min(duration, 2000));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value=(Integer) animation.getAnimatedValue();
int color=calculateColor(value);
setBackgroundColor(color);
}
});
animator.start();
}
private int calculateColor(int value){
ArgbEvaluator evaluator=new ArgbEvaluator();
float fraction=0;
int color=0;
if(value<=maxNum/2){
fraction=(float)value/(maxNum/2);
color=(Integer) evaluator.evaluate(fraction, 0xFFFF6347, 0XFFFF8C00);
}else {
fraction=((float)value-maxNum/2)/(maxNum/2);
color=(Integer) evaluator.evaluate(fraction, 0xFFFF8C00, 0XFF00CED1);
}
return color;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wSize=MeasureSpec.getSize(widthMeasureSpec);
int wMode=MeasureSpec.getMode(widthMeasureSpec);
int hSize=MeasureSpec.getSize(heightMeasureSpec);
int hMode=MeasureSpec.getMode(heightMeasureSpec);
if(wMode==MeasureSpec.EXACTLY){
mWidth=wSize;
}else {
mWidth=DensityUtil.dip2px(context, 300);
}
if(hMode==MeasureSpec.EXACTLY){
mHeight=hSize;
}else {
mHeight=DensityUtil.dip2px(context, 400);
}
System.out.println("mWidth....."+mWidth+"mHeight>>>>>"+mHeight);
setMeasuredDimension(mWidth, mHeight);
}
private String getSystemTime(){
Time time=new Time();
time.setToNow();
return time.year+"-"+time.month+"-"+time.monthDay;
}
}
在values文件下面的attr中自定义属性
<declare-styleable name="RoundIndicatorView">
<!-- 最大数值 -->
<attr name="maxNum" format="integer" />
<!-- 圆盘起始角度 -->
<attr name="startAngle" format="integer" />
<!-- 圆盘扫过的角度 -->
<attr name="sweepAngle" format="integer" />
</declare-styleable>
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android_customs="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:gravity="center_horizontal"
android:orientation="vertical" >
<com.suowei.appsuowei.myview.RoundIndicatorView
android:id="@+id/personal_coin_IndicatorView"
android:layout_width="300dip"
android:layout_height="250dp"
android_customs:maxNum="500"
android_customs:startAngle="160"
android_customs:sweepAngle="220" />
</LinearLayout>
上效果图吧