整理代码,发现了这个3年前写的一个view,记得当时也是参考了某大佬的博客写的,记不清了,因为这个view还是有一些知识点的,所以写下来记录一下吧
先看下最后的效果
上代码,具体的细节,在代码中参悟吧
样式
<declare-styleable name="RoundIndicatorView">
<!--最大数值-->
<attr name="maxNum" format="integer"/>
<!--圆盘起始角度-->
<attr name="startAngle" format="integer"/>
<!--圆盘扫过的角度-->
<attr name="sweepAngle" format="integer"/>
</declare-styleable>
代码
package com.xinxin.applicationtest.widget;
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.SweepGradient;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.xinxin.applicationtest.R;
/**
* Created by wxx on 2016/12/5 0005.
* 作用 : 仿支付宝芝麻信用分
*/
public class IndicatorView extends View {
private int sweepInWidth;//内圆弧宽度
private int sweepOutWidth;//外圆弧宽度
private int maxNum;//最大分值
private int currentNum = 1;//当前分值
private int startAngle;//圆弧开始的角度
private int sweepAngle;//圆弧的结束的角度
private int mWidth;//视图的宽
private int mHeight;//视图的高
private Paint paint;
private Paint paint_2;
private Paint paint_3;
private Paint paint_4;
private int radius;//圆弧半径
public IndicatorView(Context context) {
this(context, null);
}
public IndicatorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setBackgroundColor(0xFFFF6347);
initAttr(attrs);
initPaint();
}
private void initAttr(AttributeSet attributeSet) {
TypedArray typedArray = getContext().obtainStyledAttributes(attributeSet, 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);
sweepInWidth = dp2px(8);
sweepOutWidth = dp2px(3);
typedArray.recycle();
}
public int getCurrentNum() {
return currentNum;
}
public void setCurrentNum(int currentNum) {
this.currentNum = currentNum;
invalidate();
}
public void setCurrentNumAnim(int num) {
float duration = (float)Math.abs(num-currentNum)/maxNum *1500+500; //根据进度差计算动画时间
ObjectAnimator anim = ObjectAnimator.ofInt(this,"currentNum",num);
anim.setDuration((long) Math.min(duration,2000));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
int color = calculateColor(value);
setBackgroundColor(color);
}
});
anim.start();
}
private int calculateColor(int value){
setCurrentNum(value);
ArgbEvaluator evealuator = new ArgbEvaluator();
float fraction = 0;
int color = 0;
if(value <= maxNum/2){
fraction = (float)value/(maxNum/2);
color = (int) evealuator.evaluate(fraction,0xFFFF6347,0xFFFF8C00); //由红到橙
}else {
fraction = ( (float)value-maxNum/2 ) / (maxNum/2);
color = (int) evealuator.evaluate(fraction,0xFFFF8C00,0xFF00CED1); //由橙到蓝
}
return color;
}
/**
* 初始化所有画笔
*/
private void initPaint() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(0xffffffff);
paint_2 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint_3 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint_4 = new Paint(Paint.ANTI_ALIAS_FLAG);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
mWidth = widthSize;
} else {
mWidth = dp2px(300);
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
} else {
mHeight = dp2px(400);
}
setMeasuredDimension(mWidth,mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
radius = getMeasuredWidth()/4;
canvas.translate(mWidth /2, mHeight /2);
drawRound(canvas); //画内外圆弧
drawScale(canvas);//画圆弧上的刻度
drawIndicator(canvas);//画分值指示器
drawCenterText(canvas);//画中间的字
canvas.restore();
}
private String[] text ={"较差","中等","良好","优秀","极好"};
/** 化圆弧上的刻度 */
private void drawScale(Canvas canvas) {
canvas.save();
canvas.rotate(startAngle - 270);
float count = (float)sweepAngle / 30;
for (int i = 0; i <= 30; i++) {
if (i % 6 == 0) {
paint.setStrokeWidth(dp2px(3));
canvas.drawLine(0, -radius - sweepInWidth / 2, 0, -radius + sweepInWidth / 2 + dp2px(2), paint);
paint.setAlpha(0x90);
drawText(canvas, String.valueOf(maxNum / 30 * i), paint);
} else {
paint.setStrokeWidth(dp2px(1));
canvas.drawLine(0, -radius - sweepInWidth / 2, 0, -radius + sweepInWidth / 2, paint);
paint.setAlpha(0x50);
}
if(i == 3 || i == 9 || i == 15 || i ==21 || i == 27) {
drawText(canvas,text[(int)i/6],paint);
}
canvas.rotate(count);
}
canvas.restore();
}
/** 画刻度下方对应的分值 */
private void drawText(Canvas canvas, String score, Paint paint) {
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(dp2px(10));
float width = paint.measureText(score);
canvas.drawText(score,-width/2,-radius + sweepInWidth/2 + dp2px(15),paint);
paint.setStyle(Paint.Style.STROKE);
}
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 = dp2px(10);
RectF rectf2 = new RectF(-radius-w , -radius-w , radius+w , radius+w);
canvas.drawArc(rectf2,startAngle,sweepAngle,false,paint);
canvas.restore();
}
private int[] indicatorColor = {0xffffffff,0x00ffffff,0x99ffffff,0xffffffff};
/** 画外边缘的分值指示器 */
private void drawIndicator(Canvas canvas) {
canvas.save();
float sweep = (float) currentNum / (float) maxNum * sweepAngle;
if(currentNum > maxNum) {
sweep = sweepAngle;
}
SweepGradient sweepGradient = new SweepGradient(0, 0, indicatorColor, null);
paint_2.setShader(sweepGradient);
paint_2.setStyle(Paint.Style.STROKE);
paint_2.setStrokeWidth(sweepOutWidth);
int w = dp2px(10);
RectF rectF = new RectF(-radius - w, -radius - w, radius + w, radius + w);
canvas.drawArc(rectF,startAngle,sweep,false,paint_2);
float x = (float) ((radius+dp2px(10))*Math.cos(Math.toRadians(startAngle+sweep)));
float y = (float) ((radius+dp2px(10))*Math.sin(Math.toRadians(startAngle+sweep)));
paint_3.setStyle(Paint.Style.FILL);
paint_3.setColor(0xffffffff);
paint_3.setMaskFilter(new BlurMaskFilter(dp2px(3), BlurMaskFilter.Blur.SOLID)); //需关闭硬件加速
canvas.drawCircle(x,y,dp2px(3),paint_3);
canvas.restore();
}
/** 画中间的字 */
private void drawCenterText(Canvas canvas) {
canvas.save();
paint_4.setTextSize(radius/2);
paint_4.setColor(0xffffffff);
canvas.drawText(String.valueOf(currentNum),-paint_4.measureText(String.valueOf(currentNum))/2,0,paint_4);
String content = "信用";
if(currentNum < maxNum*1/5){
content += text[0];
}else if(currentNum >= maxNum*1/5 && currentNum < maxNum*2/5){
content += text[1];
}else if(currentNum >= maxNum*2/5 && currentNum < maxNum*3/5){
content += text[2];
}else if(currentNum >= maxNum*3/5 && currentNum < maxNum*4/5){
content += text[3];
}else if(currentNum >= maxNum*4/5){
content += text[4];
}
paint_4.setTextSize(radius/4);
Rect rect = new Rect();
paint_4.getTextBounds(content,0,content.length(),rect);
canvas.drawText(content,-rect.width()/2,rect.height(),paint_4);
canvas.restore();
}
//一些工具方法
protected int dp2px(int dp){
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
getResources().getDisplayMetrics());
}
protected int sp2px(int sp){
return (int)TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
getResources().getDisplayMetrics());
}
}
xml中引用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_credit_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context="com.xinxin.applicationtest.CreditViewActivity">
<com.xinxin.applicationtest.widget.IndicatorView
android:id="@+id/viewOne"
android:layout_width="wrap_content"
android:background="@android:color/holo_blue_dark"
android:layout_height="200dp" />
<EditText
android:id="@+id/etScore"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="start"/>
</LinearLayout>
如果使用
package com.xinxin.applicationtest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import com.xinxin.applicationtest.widget.IndicatorView;
public class CreditViewActivity extends AppCompatActivity {
private IndicatorView viewOne;
private EditText etScore;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_credit_view);
viewOne = (IndicatorView)findViewById(R.id.viewOne);
etScore = (EditText)findViewById(R.id.etScore);
}
public void start(View v) {
String trim = etScore.getText().toString().trim();
viewOne.setCurrentNumAnim(Integer.parseInt(trim));
}
}
整理公司电脑,这开发过程中下载过很多的第三方库、demo啥玩意的,特别多,好几年了,电脑上到处都是一些第三方的代码,想着整理一下,清理清理没用的,所以基本都是把每一个demo都跑一下看看是什么东西,没用的就删了,发现了这个当时写的,觉得这个里边还有一些不错的view绘制的知识点和关键API,就写下来吧。
单看是不行的,需要参悟一下view绘制过程中的一些边、弧的算法。
还有一个是芝麻信用分分析图的 点击查看 https://blog.youkuaiyun.com/wxx_csdn/article/details/90714774