对于Android开发者来说,自定义控件听起来是一件高大上的事,但同时呢也让大多数开发者感到怯步,正所谓会者不难,难者不会,只要经过学习,练习,自定义控件也很简单。最近NBA正在打的火热,今天就简单地画个篮球,感受感受自定义控件这只纸老虎。
一、先上效果图:
二、分三步走:
1.自定义属性
2.自定义View
3.使用自定义View
三、第一步:自定义属性
在res --> values 下新建attrs.xml文件(有则不用新建),代码如下:
<resources> <declare-styleable name="CustomProgressBar"> <attr name="firstColor" format="color" /> <attr name="secondColor" format="color" /> <attr name="circleWidth" format="dimension" /> <attr name="speed" format="integer" /> </declare-styleable> </resources>
解释一下上面:
1.name="CustomProgressBar":这个name值可以随便写,没有特定要求,不过一般写成自定义View的类名(后面介绍),便于标识。
2.<attr name="firstColor" format="color" />:每一个代表一个属性,在布局中会用到;name为属性名,format为该属性的类型定义,定义该属性是一个颜色类型,还是尺寸大小类型,还是一个图片,亦或是其他类型。
四、自定义View:
package com.dapeng.demo; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import java.util.Timer; import java.util.TimerTask; /** * Created by dapeng on 2017/6/13. */ public class CustomProgressBar extends View { //底色 private int mFirstColor; //进度的颜色 private int mSecondColor; //圈的宽度 private int mCircleWidth; //画笔 private Paint mPaint; //当前进度 private int mProgress; //速度 private int mSpeed; public CustomProgressBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomProgressBar(Context context) { this(context, null); } /** * 必要的初始化,获得一些自定义的值 * * @param context * @param attrs * @param defStyle */ public CustomProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //获取自定义属性的值 TypedArray arrs = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar, defStyle, 0); mFirstColor = arrs.getColor(R.styleable.CustomProgressBar_firstColor, Color.GREEN); mSecondColor = arrs.getColor(R.styleable.CustomProgressBar_secondColor, Color.RED); mCircleWidth = arrs.getDimensionPixelSize(R.styleable.CustomProgressBar_circleWidth, 20); mSpeed = arrs.getInt(R.styleable.CustomProgressBar_speed, 100); arrs.recycle(); mPaint = new Paint(); mProgress = 0; startDraw(); } /** * 利用定时器来画 */ private void startDraw() { final Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { if (mProgress == 360) { timer.cancel(); return; } mProgress++; postInvalidate(); } }; timer.schedule(task, 0, mSpeed); } @Override protected void onDraw(Canvas canvas) { float centreX = getWidth() / 2; // 圆心的x坐标 float centreY = getHeight() / 2; // 圆心的y坐标 float radius = centreX - 20;// 半径 mPaint.setStrokeWidth(mCircleWidth); // 设置画笔的粗细宽度(即圆环的宽度) mPaint.setAntiAlias(false); // 消除锯齿 mPaint.setStyle(Paint.Style.STROKE); // 设置空心 mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置画笔线条两头为圆头 mPaint.setColor(mFirstColor); // 设置底色 canvas.drawCircle(centreX, centreY, radius, mPaint); // 画出圆环 RectF oval2 = new RectF(centreX - radius, centreY - radius / 2, centreX + radius, centreY + radius / 2); // 用于定义圆弧的形状和大小的界限 canvas.drawOval(oval2, mPaint);//画出椭圆 canvas.drawLine(centreX - radius, centreY, centreX + radius, centreY, mPaint);//画直线 mPaint.setColor(mSecondColor); // 设置进度的颜色 RectF oval = new RectF(centreX - radius, centreY - radius, centreX + radius, centreY + radius); // 用于定义圆弧的形状和大小的界限 canvas.drawArc(oval, 0, mProgress, false, mPaint); // 根据进度画圆弧 canvas.drawArc(oval2, 0, mProgress, false, mPaint); // 根据进度画圆弧 canvas.drawLine(centreX - radius, centreY, centreX - radius + (radius * 2) / 360 * mProgress, centreY, mPaint);//根据进度画直线 } }
代码中的注释已经很清楚了,我在这再简单说明一下:
在xml布局文件中使用这个自定义View会调用拥有两个参数的构造函数,在这让其再调用三个参数的构造函数,在构造函数中获取自定义属性的值,然后利用定时器不断地去画篮球。要想把篮球画到手机界面,就得重写onDraw()方法,把画篮球的动作放在onDraw()中,而startDraw()方法中的postInvalidate();的作用就是不断地调用onDraw()方法进行重绘。
Ondraw()方法中的代码都很简单,不过有一个RectF类我得给大家介绍一下:
源码中的注释是这么解释的:RectF为一个矩形保存四个float坐标。矩形是由它的4条边(左,上,右下)的坐标表示的。可以直接访问这些字段。使用width()和height()来检索矩形的宽度和高度。注意:大多数方法都不检查是否正确地排列了坐标(例如,左小于等于右和顶部小于等于底部)。
如图所示:这个类是给准备要画的圆弧确定一个范围,传进去的四个参数left,top,right,bottom,确定一个矩形,然后在矩形的内部画正切椭圆
canvas.drawArc(oval, 0, mProgress, false, mPaint);这段代码就是用来画圆弧的,第一个参数就是RectF类型的,就是确定要画的圆弧的整体轨迹;第二个参数为起点,就是你想让这个圆弧从哪开始画(0代表起点在right处,-90代表起点在top处);第三个参数是这个圆弧两点之间的角度,确定圆弧的长度;第四个参数表示是否要画半径,false表示就只画一段圆弧,true会把两条半径也画出来,就是一个扇形;第五个参数就是画笔。
五、在布局中使用自定义View
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dapeng="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.dapeng.demo.CustomProgressBar android:id="@+id/CustomProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" dapeng:circleWidth="10dp" dapeng:firstColor="#FF000000" dapeng:secondColor="#FFA7433C" dapeng:speed="30" /> </RelativeLayout>
注意要加上这行代码:xmlns:dapeng="http://schemas.android.com/apk/res-auto",否则dapeng这个关键字不起作用。当然你也可以改为你想要的字段。