首先,我们来看看最简单的自定view
public class ClockView extends View {
private String TGA="ClockView";
public ClockView(Context context) {
super(context);
Log.i(TGA, "ClockView(Context context)");
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.i(TGA,"ClockView(Context context, AttributeSet attrs)");
}
@Override
protected void onDraw(Canvas canvas) {
Log.i(TGA,"onDraw()");
Paint circle=new Paint();
circle.setColor(Color.BLACK);
circle.setStyle(Paint.Style.STROKE);
canvas.drawCircle(getWidth()/2, getHeight()/2, 100,circle);
super.onDraw(canvas);
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.myclockwrite.ClockView
android:id="@+id/clockView1"
android:layout_width="200dp"
android:layout_height="200dp" />
</RelativeLayout>
值得一提的是,这个自定义view有两个构造方法。
public View (Context context)是在java代码创建视图的时候被调用,如果是从xml填充的视图,就不会调用这个
public View (Context context, AttributeSet attrs)这个是在xml创建时候被调用
结果如图:
这个view只画了一个最简单的圆形。
让我们做得更好点
下一步给这个圆添加两条直线做成时钟的样式
在此之前介绍两个方法。
save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
有save()和restore(),那么平移、缩放、旋转等操作只对save()和restore()作用域之间的代码有效。为了代码逻辑更清晰美观给ClockView添加一个surface内部类。
public class ClockView extends View {
private Surface surface;
private String TGA="ClockView";
public ClockView(Context context) {
super(context);
Log.i(TGA, "ClockView(Context context)");
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.i(TGA,"ClockView(Context context, AttributeSet attrs)");
}
public ClockView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Log.i(TGA,"ClockView(Context context, AttributeSet attrs, int defStyle)");
}
@Override
protected void onDraw(Canvas canvas) {
Log.i(TGA,"onDraw()");
surface=new Surface();
//画圆
canvas.drawCircle(getWidth()/2, getHeight()/2, 100,surface.circle);
//画指针
canvas.save();
canvas.rotate(2 / 12.0f * 360.0f,getWidth()/2, getHeight()/2);
canvas.drawPath(surface.hour_path, surface.hour_pointer);
canvas.rotate((0/60.0f-2 / 12.0f) * 360.0f,getWidth()/2, getHeight()/2);
canvas.drawPath(surface.minute_path, surface.minute_pointer);
canvas.rotate((50/60.0f-0/60.0f) * 360.0f,getWidth()/2, getHeight()/2);
canvas.drawPath(surface.second_path, surface.second_pointer);
canvas.restore();
super.onDraw(canvas);
}
private class Surface{
//圆画笔
public Paint circle;
//时针画笔和路径
public Paint hour_pointer;
public float hour_pointer_width;
public float hour_lenght=60;
public Path hour_path;
//分针画笔和路径
public Path minute_path;
public Paint minute_pointer;
public float minute_poiner_width;
public float minute_lenght=80;
//秒针画笔和路径
public Paint second_pointer;
public float second_lenght=95;
public Path second_path;
public float second_poiner_width;
public Surface() {
Init();
}
public void Init(){
circle=new Paint();
circle.setColor(Color.BLACK);
circle.setStyle(Paint.Style.STROKE);
circle.setAntiAlias(true);
hour_pointer=new Paint();
hour_pointer.setColor(Color.BLACK);
hour_pointer.setAntiAlias(true);
hour_pointer_width= (float) (0.5 * 10);
hour_pointer.setStyle(Paint.Style.STROKE);
hour_pointer.setStrokeWidth(hour_pointer_width);
hour_path=new Path();
hour_path.moveTo(getWidth()/2, getHeight()/2+5);
hour_path.rLineTo(0,-hour_lenght);
minute_path=new Path();
minute_path.moveTo(getWidth()/2, getHeight()/2+8);
minute_path.rLineTo(0, -minute_lenght);
minute_pointer=new Paint();
minute_pointer.setColor(Color.BLACK);
minute_pointer.setAntiAlias(true);
minute_poiner_width= (float) (0.5 * 10);
minute_pointer.setStyle(Paint.Style.STROKE);
minute_pointer.setStrokeWidth(minute_poiner_width);
second_path=new Path();
second_path.moveTo(getWidth()/2, getHeight()/2+11);
second_path.rLineTo(0, -second_lenght);
second_pointer=new Paint();
second_pointer.setColor(Color.BLACK);
second_pointer.setAntiAlias(true);
second_poiner_width= (float) (0.5 * 10);
second_pointer.setStyle(Paint.Style.STROKE);
second_pointer.setStrokeWidth(second_poiner_width);
}
}
}
这时候我们的时钟稍微有点样子了
让我们做得更好点
做钟的话肯定要要钟动起来,先去百度个倒计时方法,添加到MainActivity
public class MainActivity extends Activity {
private ClockView clockView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
clockView=(ClockView) findViewById(R.id.clockView1);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
handler.post(runnable);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
handler.removeCallbacks(runnable);
}
Handler handler=new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.i("test", "run");
clockView.updateTime();
handler.postDelayed(this, 1000);
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
再ClockView实现updateTime()
public void updateTime(){
Date now=new Date();
curtime.setTime(now);
invalidate();
}
此时这个自定义view终于有点feel了
让我们做得更好点
虽然这时候clock已经可以像真正的钟一样动了,但是感觉还是太粗糙了。现在代码逻辑基本都实现了,接下来替换些图片,让clock显得高端大气些。
去网上找了一个时钟的背景图片,画图片代码很简单
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), R.drawable.clock);
canvas.drawBitmap(bmp ,0 ,0,null);
比较麻烦的是适配问题,自定义view要能根据布局大小自动调节图画比例。
主要思路是根据图片原始大小与布局大小的比例—》对每个部位按各种比例缩放。
package com.example.myclockwrite;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.Calendar;
import java.util.Date;
public class ClockView extends View {
private Surface surface;
private Calendar curtime;
private String TGA="ClockView";
private float hours;
private float minutes;
private float seconds;
private Context context;
public ClockView(Context context) {
super(context);
Log.i(TGA, "ClockView(Context context)");
curtime=Calendar.getInstance();
this.context=context;
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.i(TGA,"ClockView(Context context, AttributeSet attrs)");
curtime=Calendar.getInstance();
this.context=context;
}
public ClockView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Log.i(TGA,"ClockView(Context context, AttributeSet attrs, int defStyle)");
curtime=Calendar.getInstance();
this.context=context;
}
@Override
protected void onDraw(Canvas canvas) {
Log.i(TGA,"onDraw()");
//画背景图片
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), R.drawable.clock);
float xs=(float)getWidth()/(float)bmp.getWidth();
float ys=(float)getHeight()/(float)bmp.getHeight();
Matrix matrix=new Matrix();
matrix.postScale(xs,ys);//对图片进行缩放
Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(),bmp.getHeight(),matrix,true);
canvas.drawBitmap(dstbmp,0 ,0,null);
//初始化时间
hours=curtime.get(Calendar.HOUR);
minutes=curtime.get(Calendar.MINUTE);
seconds=curtime.get(Calendar.SECOND);
//画指针
surface=new Surface(getWidth(),getHeight(),xs,ys);
canvas.save();
canvas.rotate((hours+(minutes/60.0f))/ 12.0f * 360.0f,getWidth()/2, getHeight()/2);
canvas.drawPath(surface.hour_path, surface.hour_pointer);
canvas.rotate((minutes/60.0f-(hours+(minutes/60.0f)) / 12.0f) * 360.0f,getWidth()/2, getHeight()/2);
canvas.drawPath(surface.minute_path, surface.minute_pointer);
canvas.rotate((seconds/60.0f-minutes/60.0f) * 360.0f,getWidth()/2, getHeight()/2);
canvas.drawPath(surface.second_path, surface.second_pointer);
canvas.restore();
super.onDraw(canvas);
}
private class Surface{
//圆画笔
// public Paint circle;
public Paint pic;
//时针画笔和路径
public Paint hour_pointer;
public float hour_pointer_width;
public float hour_lenght;
public Path hour_path;
//分针画笔和路径
public Path minute_path;
public Paint minute_pointer;
public float minute_poiner_width;
public float minute_lenght;
//秒针画笔和路径
public Paint second_pointer;
public float second_lenght;
public Path second_path;
public float second_poiner_width;
public int width;
public int height;
public float scale;
public Surface(int width,int height,float xs,float ys) {
this.width=width;
this.height=height;
if(xs>ys){
this.scale=ys;
}else{
this.scale=xs;
}
second_lenght=width*0.7f/2;
minute_lenght=width*0.6f/2;
hour_lenght=width*0.4f/2;
Init();
}
public void Init(){
// circle=new Paint();
// circle.setColor(Color.BLACK);
// circle.setStyle(Paint.Style.STROKE);
// circle.setAntiAlias(true);
hour_pointer=new Paint();
hour_pointer.setColor(Color.BLACK);
hour_pointer.setAntiAlias(true);
hour_pointer_width= (float) (scale* 6);
hour_pointer.setStyle(Paint.Style.STROKE);
hour_pointer.setStrokeWidth(hour_pointer_width);
hour_path=new Path();
hour_path.moveTo(width/2, height/2+scale*5);
hour_path.rLineTo(0,-hour_lenght);
minute_path=new Path();
minute_path.moveTo(width/2, height/2+scale*8);
minute_path.rLineTo(0, -minute_lenght);
minute_pointer=new Paint();
minute_pointer.setColor(Color.BLACK);
minute_pointer.setAntiAlias(true);
minute_poiner_width= (float) (scale* 4);
minute_pointer.setStyle(Paint.Style.STROKE);
minute_pointer.setStrokeWidth(minute_poiner_width);
second_path=new Path();
second_path.moveTo(width/2, height/2+scale*11);
second_path.rLineTo(0, -second_lenght);
second_pointer=new Paint();
second_pointer.setColor(Color.BLACK);
second_pointer.setAntiAlias(true);
second_poiner_width= (float) (scale * 2);
second_pointer.setStyle(Paint.Style.STROKE);
second_pointer.setStrokeWidth(second_poiner_width);
Log.i(TGA, hour_lenght+" "+minute_lenght+" "+second_lenght);
}
}
public void updateTime() {
Date now=new Date();
curtime.setTime(now);
invalidate();
}
}
源码:http://download.csdn.net/detail/u013122203/6738791