自定义控件顾名思义,主要用于开发系统没有提供的控件类型。要自定义控件,首先要创建一个类继承View或View的子类,也可以将各种控件组合起来以实现自定义的目的。
public class TimerView extends View{
private Paint mPaint;
private Rect mRect;
public TimerView(Context context) {
this(context, null);
}
public TimerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TimerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context ,AttributeSet attrs){
mPaint = new Paint();
mRect = new Rect();
}
}
<declare-styleable name="TimerView" >
<attr name="ProgressColor" format="color"/>
<attr name="ProgressWidth" format="dimension"/>
<attr name="TextSize" format="dimension"/>
<attr name="TextColor" format="color"/>
</declare-styleable>
onDraw方法中传入的参数Canvas是一个类似于画板的类,于它常常配合使用的类Paint,它作用类似于画笔,将画板Canvas和画笔Paint配合使用,就能绘制出一个View视图。
canvas常用方法:
canvas.drawCircle(…..); 绘制圆形
canvas.drawArc(RectF rectf,float startAngle,float sweepAngle,boolean useCenter,Paint paint);
绘制圆弧,参数特别说明下:
1、RectF作用类似于Rect,RectF的构造方法提供了四个参数,分别为左,上,右,下,如
RectF rectf = new RectF(0,0,100,100),则RectF是一个以(0,0)点为左上坐标,(100,100)为右下坐标的一个矩形范围,将这个参数传入drawArc()方法中,即可将圆弧的范围确定下来。
2、starAngle为起始角度,sweepAngle为扫过的角度(不是最终的角度)。而useCenter的作用为是否与圆心进行连线,若连线则画出类似于扇形的图案。
canvas.drawText (String text,float x, float y, Paint paint)
第一个参数为字符串,第二、三个参数定义了一个坐标(X,Y)作为起始坐标绘制,而paint中可以用
Paint.getTextBounds (String text, int start, int end, Rect bounds)来获取字符的范围,其值保存在Rect中。
在自定义控件中,我们可以通过declare-styleable在attrs.xml中声明我们的控件,然后在代码中以R.styleable.XXX来获取。然后通过TypeArray类来获取特定的属性,如在attrs中以定义如下属性
<declare-styleable name="TimerView" >
<attr name="ProgressColor" format="color"/>
<attr name="ProgressWidth" format="dimension"/>
<attr name="TextSize" format="dimension"/>
<attr name="TextColor" format="color"/>
</declare-styleable>
在代码中可以用如下方法获得:
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.TimerView);
float mTextSize = typedArray.getDimension(R.styleable.TimerView_TextSize, 50);
int mProgressColor = typedArray.getColor(R.styleable.TimerView_ProgressColor, Color.RED);
float mProgressWidth = typedArray.getDimension(R.styleable.TimerView_ProgressWidth, 3);
在Xml文件中若要引用这些这些属性,需添加命名空间:
xmlns:timer="http://schemas.android.com/apk/res-auto"
这里的res-auto为自动适配。
handler一个重要的作用为保证各个线程之间的同步运行。在android中,如网络请求等费时操作需要新建立线程进行以防止UI线程阻塞,而handler则作为线程之间的桥梁存在。Handler的声明及初始化如下:
public static class MyHanler extends Handler{
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
Handler中的抽象方法handlerMessage必须进行重写,每当程序接受到一个Message,则进入handlerMessage进行处理。
handler常用方法:
public final boolean sendMessage (Message msg);
传递一个Message对象
public final boolean sendMessageDelayed (Message msg, long delayMillis);
延迟一定时间发送信息,以毫秒为单位。
public boolean sendMessageAtTime (Message msg, long uptimeMillis);
在规定时间发送信息。
public final boolean sendEmptyMessage (int what);
在不需要传送message时,可以使用此方法,此方法主要功能为通知UI线程,本线程内工作以完毕且不需要返回数据。
Message类的声明及初始化代码如下:
Message message = hanler.obtainMessage();
//不要使用Message message = new Message();
使用handler.obtainMessage();能够更好的管理内存,当handler销毁时,Message也会释放,不会浪费内存空间。
Message的属性一共有如下几个
- obj obj类型,可以传递所有对象。
- args1 int类型
- args2 int类型
- what int类型,主要用于分辨不同的Message。