初次自定义view,绘制了一个表,点击表针会转动。自定义的控件的尽量将可以从外部设置的属性暴露出来,这样增加控件适用场合和灵活性。
思路
- extends view并实现其中的onDraw方法来实现绘制图形
- 重写其中的ClockView(Context context, AttributeSet attrs)来实现在xml中的引用
- implements View.OnClickListener来实现监听点击
- 重写onSizeChanged方法实现部分参数的初始化和对界面尺寸变化的适应
参数说明
private int count_clicked=0;
private float mborderwidth;
private int mbordercolor;
private Paint mPaint;
private RectF mBounds;
private float mWidth;
private float mHeight;
private float mRadius;
private float smalllength;
private float largerlength;
1.创建一个ClockView继承自view并实现View.OnClickListener方法,一定要记得重载其中的第二个构造器,这样才能在xml中引用
public class ClockView extends View implements View.OnClickListener
public ClockView(Context context)
public ClockView(Context context, AttributeSet attrs)
public ClockView(Context context, AttributeSet attrs, int defStyleAttr)
2.为了在xml中设置属性,为控件设置属性,在values下创建attrs.xml文件
<resources>
<declare-styleable name="ClockView">
<attr name="border_color" format="color"/>
<attr name="border_width" format="dimension"/>
</declare-styleable>
</resources>
3.重写构造方法,从xml中解析属性,初始化一些数据
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs)
//获取xml中的自定义属性
TypedArray typedArray=context.getTheme().obtainStyledAttributes(
attrs,R.styleable.ClockView,0,0)
mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000)
mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2)
InitPara()
setOnClickListener(this)
}
4.初始化画笔并处理点击事件,每次点击旋转6度,一共可以旋转60次,count_clicked记录需要旋转的次数(在每个构造器中添加InitPara(); setOnClickListener(this);)
private void InitPara(){
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mborderwidth);
mPaint.setColor(mbordercolor);
}
@Override
public void onClick(View v) {
count_clicked++;
if(count_clicked%60==0){
count_clicked=0;
}
invalidate();
}
5.重写onSizeChanged,并进行一些数据初始化
/**
* 当界面的尺寸发生改变时调用
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
mWidth=mBounds.right-mBounds.left;
mHeight=mBounds.bottom-mBounds.top;
if(mHeight<mWidth){
mRadius=mHeight/4;
}else{
mRadius=mWidth/4;
}
smalllength=30;
largerlength=60;
}
6.自定义ClockDraw(canvas, count_clicked)用来绘制自定义的图形
private void ClockDraw(Canvas canvas,int count){
//绘制底色和矩形框
canvas.drawColor(0xff000000)
canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
mBounds.centerY() - (float)0.9*mHeight/2,
mBounds.centerX() + (float)0.9*mWidth/2,
mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint)
mPaint.setColor(mbordercolor)
//绘制表盘的刻度
float start_x,start_y
float end_x,end_y
for(int i=0
{
start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6)
start_y=mRadius*(float)Math.sin(Math.PI/180*i*6)
if(i%5==0){
end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6)
end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6)
}else {
end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6)
end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6)
}
start_x+=mBounds.centerX()
start_y+=mBounds.centerY()
end_x+=mBounds.centerX()
end_y+=mBounds.centerY()
canvas.drawLine(start_x,start_y,end_x,end_y,mPaint)
}
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint)
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint)
canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY())
canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint)
}
7.重写onDraw方法,调用自己的Draw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
ClockDraw(canvas, count_clicked);
}
在xml中调用自定义的view,设置颜色和线条粗细
<com.demo.eric.defineview.ClockView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:border_color="#eaf1e90b"
app:border_width="4dp"/>
完成!!!

总结:
重点是onDraw中的重写,在onDraw中进行一系列的图形绘制;canvas作为画布,利用paint在canvas上调用canvas.drawXXX(X,X,X,……,paint)绘制自己想要的图形。
ClockView整体源码
/**
* Created by Administrator on 2016/1/7 0007.
*/
public class ClockView extends View implements View.OnClickListener {
private int count_clicked=0;
private float mborderwidth;
private int mbordercolor;
private Paint mPaint;
private RectF mBounds;
private float mWidth;
private float mHeight;
private float mRadius;
private float smalllength;
private float largerlength;
public ClockView(Context context) {
super(context);
setOnClickListener(this);
InitPara();
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray=context.getTheme().obtainStyledAttributes(
attrs,R.styleable.ClockView,0,0);
mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000);
mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);
InitPara();
setOnClickListener(this);
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
InitPara();
setOnClickListener(this);
}
private void InitPara(){
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mborderwidth);
mPaint.setColor(mbordercolor);
}
/**
* 当界面的尺寸发生改变时调用
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
mWidth=mBounds.right-mBounds.left;
mHeight=mBounds.bottom-mBounds.top;
if(mHeight<mWidth){
mRadius=mHeight/4;
}else{
mRadius=mWidth/4;
}
smalllength=30;
largerlength=60;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
ClockDraw(canvas, count_clicked);
}
private void ClockDraw(Canvas canvas,int count){
canvas.drawColor(0xff000000);
canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
mBounds.centerY() - (float)0.9*mHeight/2,
mBounds.centerX() + (float)0.9*mWidth/2,
mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
mPaint.setColor(mbordercolor);
float start_x,start_y;
float end_x,end_y;
for(int i=0;i<60;i++)
{
start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
if(i%5==0){
end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
}else {
end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
}
start_x+=mBounds.centerX();
start_y+=mBounds.centerY();
end_x+=mBounds.centerX();
end_y+=mBounds.centerY();
canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
}
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);
canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());
canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);
}
@Override
public void onClick(View v) {
count_clicked++;
if(count_clicked%60==0){
count_clicked=0;
}
invalidate();
}
}