初次自定义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();//重新绘制,调用onDraw
}
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;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);
}
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);
//获取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);
}
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();
}
}