android官方给出的自定义控件的步骤:
1、创建View
2、处理View的布局
3、绘制View
4、与用户进行交互
5、优化已定义的View
强调内容
自定义属性:
自定义属性通常写在在res/values/attrs.xml文件中 ,使用自定义属性的时候需要指定命名空间,在android studio,用http://schemas.android.com/apk/res/res-auto
在 xml中创建了一个view时,所有在xml中声明的属性都会被传入到view的构造方法中的AttributeSet类型的参数当中。
通过调用Context的obtainStyledAttributes()方法返回一个TypedArray对象。然后直接用TypedArray对象获取自定义属性的值。
由于TypedArray对象是共享的资源,所以在获取完值之后必须要调用recycle()方法来回收。
布局如下:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.mycolorarcprogressbar.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="Start"/>
<com.example.mycolorarcprogressbar.MyColorProgressBar
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:id="@+id/bar1"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:text="start"
/>
<com.example.mycolorarcprogressbar.MyColorProgressBar
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:id="@+id/bar2"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn3"
android:text="start"
/>
<com.example.mycolorarcprogressbar.MyColorProgressBar
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:id="@+id/bar3"
/>
LinearLayout>
ScrollView>
自定义VIew的属性:
<resources>
<declare-styleable name="MyColorProgressBar">
<attr name="ColorArcProgressBar_front_color1" format="color"/>
<attr name="ColorArcProgressBar_front_color2" format="color"/>
<attr name="ColorArcProgressBar_front_color3" format="color"/>
<attr name="ColorArcProgressBar_total_engle" format="color"/>
<attr name="ColorArcProgressBar_back_width" format="color"/>
<attr name="ColorArcProgressBar_front_width" format="color"/>
<attr name="ColorArcProgressBar_is_need_title" format="color"/>
<attr name="ColorArcProgressBar_is_need_content" format="color"/>
<attr name="ColorArcProgressBar_is_need_unit" format="color"/>
<attr name="ColorArcProgressBar_is_need_dial" format="color"/>
<attr name="ColorArcProgressBar_string_unit" format="color"/>
<attr name="ColorArcProgressBar_string_title" format="color"/>
<attr name="ColorArcProgressBar_current_value" format="color"/>
<attr name="ColorArcProgressBar_max_value" format="color"/>
declare-styleable>
resources>
package com.example.mycolorarcprogressbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.mycolorarcprogressbar.MyColorProgressBar;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button mButton1,mButton2,mButton3;
private MyColorProgressBar mBar1,mBar2,mBar3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBar1 = (MyColorProgressBar) findViewById(R.id.bar1);
mButton1 = (Button) findViewById(R.id.btn1);
mBar2 = (MyColorProgressBar) findViewById(R.id.bar2);
mButton2 = (Button) findViewById(R.id.btn2);
mBar3 = (MyColorProgressBar) findViewById(R.id.bar3);
mButton3 = (Button) findViewById(R.id.btn3);
mButton1.setOnClickListener(this);
mButton2.setOnClickListener(this);
mButton3.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn1:
//进度条当前的值
mBar1.setCurrentValues(100);
break;
case R.id.btn2:
mBar2.setCurrentValues(50);
break;
case R.id.btn3:
mBar3.setCurrentValues(30);
break;
}
}
}
package com.example.mycolorarcprogressbar;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.animation.ValueAnimator;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.DisplayMetrics;
import android.view.WindowManager;
public class MyColorProgressBar extends View {
private int mWidth,mHeight;
//直径
private int diameter = 500;
//圆心
private float centerX,centerY;
//定义画笔
private Paint allArcPaint;
//进度条的画笔
private Paint progressPaint;
//角度的画笔
private Paint degreePaint;
private RectF bgRect;
//属性动画
private ValueAnimator progressAnimator;
//刚开始角度
private float startAngle = 135;
//渐变角度
private float sweepAngle = 270;
//当前角度
private float currentAngle = 0;
//最终角度
private float lastAngle;
private int[] colors = new int[]{Color.BLUE, Color.YELLOW, Color.RED, Color.RED};
private float maxValues = 60;
private float curValues = 0;
private float bgArcWidth = dipToPx(2);
private float progressWidth = dipToPx(10);
private float textSize = dipToPx(60);
private int aniSpeed = 1000;
private float longdegree = dipToPx(13);
private float shortdegree = dipToPx(5);
private final int DEGREE_PROGRESS_DISTANCE = dipToPx(8);
private String longDegreeColor = "#111111";
private String shortDegreeColor = "#111111";
private String bgArcColor = "#111111";
private boolean isShowCurrentSpeed = true;
private String hintString = "Km/h";
private boolean isNeedTitle;
private boolean isNeedUnit;
private boolean isNeedDial;
private boolean isNeedContent;
private String titleString;
// sweepAngle / maxValues 的值
private float k;
public MyColorProgressBar(Context context) {
super(context, null);
initView();
}
public MyColorProgressBar(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initCofig(context, attrs);
initView();
}
public MyColorProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initCofig(context, attrs);
initView();
}
//初始布局配置
private void initCofig(Context context, AttributeSet attrs) {
//获得所有的属性值
//R.styleable.MyColorProgressBar是需要在values下建一个attrs固定目录
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyColorProgressBar);
int color1 = a.getColor(R.styleable.MyColorProgressBar_ColorArcProgressBar_front_color1, Color.MAGENTA);
int color2 = a.getColor(R.styleable.MyColorProgressBar_ColorArcProgressBar_front_color2, Color.GREEN);
int color3 = a.getColor(R.styleable.MyColorProgressBar_ColorArcProgressBar_front_color3, Color.BLUE);
colors = new int[]{color1, color2, color3};
sweepAngle = a.getInteger(R.styleable.MyColorProgressBar_ColorArcProgressBar_total_engle, 270);
bgArcWidth = a.getDimension(R.styleable.MyColorProgressBar_ColorArcProgressBar_back_width, dipToPx(2));
progressWidth = a.getDimension(R.styleable.MyColorProgressBar_ColorArcProgressBar_front_width, dipToPx(10));
isNeedTitle = a.getBoolean(R.styleable.MyColorProgressBar_ColorArcProgressBar_is_need_title, false);
isNeedContent = a.getBoolean(R.styleable.MyColorProgressBar_ColorArcProgressBar_is_need_content, false);
isNeedUnit = a.getBoolean(R.styleable.MyColorProgressBar_ColorArcProgressBar_is_need_unit, false);
isNeedDial = a.getBoolean(R.styleable.MyColorProgressBar_ColorArcProgressBar_is_need_dial, false);
hintString = a.getString(R.styleable.MyColorProgressBar_ColorArcProgressBar_string_unit);
titleString = a.getString(R.styleable.MyColorProgressBar_ColorArcProgressBar_string_title);
curValues = a.getFloat(R.styleable.MyColorProgressBar_ColorArcProgressBar_current_value, 0);
maxValues = a.getFloat(R.styleable.MyColorProgressBar_ColorArcProgressBar_max_value, 60);
setCurrentValues(curValues);
setMaxValues(maxValues);
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
int height= (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
setMeasuredDimension(width, height);
}
private void initView() {
diameter = 3 * getScreenWidth() / 5;
//弧形的矩阵区域
bgRect = new RectF();
bgRect.top = longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE;
bgRect.left = longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE;
bgRect.right = diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE);
bgRect.bottom = diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE);
//圆心
centerX = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE)/2;
centerY = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE)/2;
//外部刻度线
degreePaint = new Paint();
degreePaint.setColor(Color.parseColor(longDegreeColor));
//整个弧形
allArcPaint = new Paint();
allArcPaint.setAntiAlias(true);
allArcPaint.setStyle(Paint.Style.STROKE);
allArcPaint.setStrokeWidth(bgArcWidth);
allArcPaint.setColor(Color.parseColor(bgArcColor));
allArcPaint.setStrokeCap(Paint.Cap.ROUND);
//当前进度的弧形
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeCap(Paint.Cap.ROUND);
progressPaint.setStrokeWidth(progressWidth);
progressPaint.setColor(Color.GREEN);
}
@Override
protected void onDraw(Canvas canvas) {
//抗锯齿
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
if (isNeedDial) {
//画刻度线
for (int i = 0; i < 40; i++) {
if (i > 15 && i < 25) {
canvas.rotate(9, centerX, centerY);
continue;
}
if (i % 5 == 0) {
degreePaint.setStrokeWidth(dipToPx(2));
degreePaint.setColor(Color.parseColor(longDegreeColor));
canvas.drawLine(centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE, centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - longdegree, degreePaint);
} else {
degreePaint.setStrokeWidth(dipToPx(1.4f));
degreePaint.setColor(Color.parseColor(shortDegreeColor));
canvas.drawLine(centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longdegree - shortdegree) / 2, centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longdegree - shortdegree) / 2 - shortdegree, degreePaint);
}
canvas.rotate(9, centerX, centerY);
}
}
//整个弧
canvas.drawArc(bgRect, startAngle, sweepAngle, false, allArcPaint);
//设置渐变色
SweepGradient sweepGradient = new SweepGradient(centerX, centerY, colors, null);
Matrix matrix = new Matrix();
matrix.setRotate(130, centerX, centerY);
sweepGradient.setLocalMatrix(matrix);
progressPaint.setShader(sweepGradient);
//当前进度
canvas.drawArc(bgRect, startAngle, currentAngle, false, progressPaint);
invalidate();
}
//设置最大值 maxValues
public void setMaxValues(float maxValues) {
this.maxValues = maxValues;
k = sweepAngle/maxValues;
}
//设置当前值 currentValues
public void setCurrentValues(float currentValues) {
if (currentValues > maxValues) {
currentValues = maxValues;
}
if (currentValues < 0) {
currentValues = 0;
}
this.curValues = currentValues;
lastAngle = currentAngle;
setAnimation(lastAngle, currentValues * k, aniSpeed);
}
// 设置整个圆弧宽度 bgArcWidth
public void setBgArcWidth(int bgArcWidth) {
this.bgArcWidth = bgArcWidth;
}
//设置进度宽度 progressWidth
public void setProgressWidth(int progressWidth) {
this.progressWidth = progressWidth;
}
//设置速度文字大小 mtextSize
public void setTextSize(int textSize) {
this.textSize = textSize;
}
// 设置直径大小 diameter
public void setDiameter(int diameter) {
this.diameter = dipToPx(diameter);
}
// 为进度设置动画 last current
private void setAnimation(float last, float current, int length) {
progressAnimator = ValueAnimator.ofFloat(last, current);
progressAnimator.setDuration(length);
progressAnimator.setTarget(currentAngle);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAngle= (float) animation.getAnimatedValue();
curValues = currentAngle/k;
}
});
progressAnimator.start();
}
private int dipToPx(float dip) {
float density = getContext().getResources().getDisplayMetrics().density;
return (int)(dip * density + 0.5f * (dip >= 0 ? 1 : -1));
}
private int getScreenWidth() {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
public void setIsShowCurrentSpeed(boolean isShowCurrentSpeed) {
this.isShowCurrentSpeed = isShowCurrentSpeed;
}
}