安卓开发中自定义View之onMeasure(),onLayout(),onDraw()讲解(三)


  自定义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 的复杂使用,模拟支付宝芝麻信用分动画效果。

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>
上效果图吧


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值