1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw
我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView">
<attr name="radius" format="dimension"/>
<attr name="stripeWidth" format="dimension"/> <!--色带宽度-->
<attr name="percent" format="integer"/> <!--百分比 最大值为100-->
<attr name="smallColor" format="color"/> <!--色带宽度-->
<!--外圈颜色-->
<attr name="bigColor" format="color"/>
<!--中间字体颜色-->
<attr name="centerTextSize" format="dimension"/>
<!--色带宽度-->
</declare-styleable>
</resources>
创建一个 Myview类来继承View 来实现它的及格有参构造
public class MyView extends View {
//圆的半径
private float mRadius;
//色带的宽度
private float mStripeWidth;
//总体大小
private int mHeight;
private int mWidth;
//动画位置百分比进度
private int mCurPercent;
//实际百分比进度
private int mPercent;
//圆心坐标
private float x;
private float y;
//要画的弧度
private int mEndAngle;
//小圆的颜色
private int mSmallColor;
//大圆颜色
private int mBigColor;
//中心百分比文字大小
private float mCenterTextSize;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 获取自定义属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, 0);
//获取色带的宽度
mStripeWidth = a.getDimension(R.styleable.MyView_stripeWidth, PxUtils.dpToPx(30, context));
//获取当前的百分比
mCurPercent = a.getInteger(R.styleable.MyView_percent, 0);
//获取小园的颜色
mSmallColor = a.getColor(R.styleable.MyView_smallColor, Color.BLACK);
//获取大圆的颜色
mBigColor = a.getColor(R.styleable.MyView_bigColor, Color.WHITE);
//获取中心文字的大小
mCenterTextSize = a.getDimensionPixelSize(R.styleable.MyView_centerTextSize, PxUtils.spToPx(50, context));
//获取园的半径
mRadius = a.getDimensionPixelSize(R.styleable.MyView_radius, PxUtils.dpToPx(100, context));
}
//测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取测量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//获取测量大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//如果为确定大小值,则圆的半径为宽度/2
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
mRadius = widthSize / 2;
x = widthSize / 2;
y = heightSize / 2;
mWidth = widthSize;
mHeight = heightSize;
}
//如果为wrap_content 那么View大小为圆的半径大小*2
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
mWidth = (int) (mRadius * 2);
mHeight = (int) (mRadius * 2);
x = mRadius;
y = mRadius;
}
//设置视图的大小
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
mEndAngle = (int) (mCurPercent * 3.6);
//绘制大圆
Paint bigCirclePaint = new Paint();
bigCirclePaint.setAntiAlias(true);
bigCirclePaint.setColor(mBigColor);
canvas.drawCircle(x, y, mRadius, bigCirclePaint);
//饼状图
Paint sectorPaint = new Paint();
sectorPaint.setColor(mSmallColor);
sectorPaint.setAntiAlias(true);
RectF rect = new RectF(0, 0, mWidth, mHeight);
canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);
//绘制小圆,颜色透明
Paint smallCirclePaint = new Paint();
smallCirclePaint.setAntiAlias(true);
smallCirclePaint.setColor(mBigColor);
canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);
//绘制文本
Paint textPaint = new Paint();
String text = mCurPercent + "%";
textPaint.setTextSize(mCenterTextSize);
float textLength = textPaint.measureText(text);
textPaint.setColor(Color.RED);
canvas.drawText(text, x - textLength / 2, y, textPaint);
super.onDraw(canvas);
}
public void setmSmallColor(int mSmallColor) {
this.mSmallColor = mSmallColor;
invalidate();
}
//重置
public void setReset(int percent) {
mCurPercent = percent;
invalidate();
}
//外部设置百分比数
public void setPercent(int percent) {
if (percent > 100) {
throw new IllegalArgumentException("percent must less than 100!");
}
setCurPercent(percent);
}
//内部设置百分比 用于动画效果
private void setCurPercent(int percent) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 101; i++) {
mCurPercent = i;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
postInvalidate();
}
}
}).start();
}
}
对应的布局 主页面 坑点 布局里面的Myview标签控件 根据自己的创建的类 自动生成 里面对应的dabin属性自定义的 别忘导包 对应的这个布局的宽度高度有如下一句话
xmlns:dabin="http://schemas.android.com/apk/res-auto"
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:dabin="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.view.MainActivity">
<com.example.view.MyView
android:id="@+id/my_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
dabin:stripeWidth="15dp"
dabin:centerTextSize="16sp"
dabin:percent="78"
/>
<Button
android:id="@+id/start"
android:text="开始"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="26dp"
android:layout_marginStart="26dp"
android:layout_marginBottom="117dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:text="重置"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/start"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="51dp"
android:layout_marginEnd="51dp"
android:id="@+id/reset" />
<Button
android:text="改变外圈颜色"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignLeft="@+id/reset"
android:layout_alignStart="@+id/reset"
android:layout_marginLeft="19dp"
android:layout_marginStart="19dp"
android:layout_marginTop="56dp"
android:id="@+id/button2" />
</RelativeLayout>
对应创建 一个转换Dip dp的的单位的类,可有可无,但是我对应的用了,这点根据自己需求 PxUtils
public class PxUtils {
public static int dpToPx(int dp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
public static int spToPx(int sp,Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
}
最后 就是对应的主方法 Activity
public class MainActivity extends AppCompatActivity {
private MyView myView;
private Button mButton;
private Button mReset;
private Button mColor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myView = (MyView) findViewById(R.id.my_view);
mButton = (Button) findViewById(R.id.start);
mReset = (Button) findViewById(R.id.reset);
mColor = (Button) findViewById(R.id.button2);
//开始
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int n = (int) (Math.random() * 100);
myView.setPercent(n);
}
});
//重置
mReset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setReset(78);
}
});
mColor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setmSmallColor(Color.BLUE);
}
});
}
}
以上就能实现一个view圆 联动进度条 ,默认是78,转到100,有三个对应的按钮 点击 分别是重设 回到默认的 ,开始 :开始转动 ,第三个改变View的颜色