通过继承View类,我们可以自定义自己需求的复杂控件。本例实现了一个自定义的时钟。
效果如下:
代码如下:
package com.example.test;
import java.util.Calendar;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
public class Clock extends View implements Runnable {
//表盘图像资源ID
private int clockImageResourceID;
//表盘图像缩放比例
private float scale;
private Bitmap bitmap;
//原始图像中表盘中心点横坐标相当于图像宽度的比例
private float centerWidthScale;
//原始图像中表盘中心点纵坐标相当于图像高度的比例
private float centerHeightScale;
//在原始表盘中分针的长度
private int minuteSize;
//在原始表盘中时针的长度
private int hourSize;
private Handler handler=new Handler();
public Clock(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
//本例未使用命名空间 null
clockImageResourceID=attrs.getAttributeResourceValue(null,"clockImageSrc",0);
if(clockImageResourceID>0){
bitmap=BitmapFactory.decodeResource(getResources(), clockImageResourceID);
}
scale=attrs.getAttributeFloatValue(null, "scale", 1);
centerWidthScale=attrs.getAttributeFloatValue(null, "centerWidthScale" ,bitmap.getHeight()/2);
centerHeightScale=attrs.getAttributeFloatValue(null, "centerHeightScale" ,bitmap.getWidth()/2);
//将时针分针的长度缩放
minuteSize=(int)(attrs.getAttributeIntValue(null, "minuteSize", 0)*scale);
hourSize=(int)(attrs.getAttributeIntValue(null, "hourSize", 0)*scale);
int currentSecond=Calendar.getInstance().get(Calendar.SECOND);
//当秒钟在12点方向时 执行run方法
handler.postDelayed(this, (60-currentSecond)*1000);
}
//view分离时调用
@Override
protected void onDetachedFromWindow() {
// TODO Auto-generated method stub
super.onDetachedFromWindow();
handler.removeCallbacks(this);
}
public void run() {
// TODO Auto-generated method stub
//重绘
invalidate();
//重新设定定时器60s后启用
handler.postDelayed(this, 60*1000);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//根据图像的实际大小等比例设置view的大小
setMeasuredDimension((int)(bitmap.getWidth()*scale), (int)(bitmap.getHeight()*scale));
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint=new Paint();
Rect src=new Rect();
Rect target=new Rect();
src.left=0;
src.top=0;
src.right=bitmap.getWidth();
src.bottom=bitmap.getHeight();
target.left=0;
target.top=0;
target.bottom=(int)(src.bottom*scale);
target.right=(int)(src.right*scale);
//画表盘
canvas.drawBitmap(bitmap, src, target,paint);
//计算表盘中心点的横坐标
float centerX=bitmap.getWidth()*scale*centerWidthScale;
//计算表盘中心点的纵坐标
float centerY=bitmap.getHeight()*scale*centerHeightScale;
canvas.drawCircle(centerX, centerY, 5, paint);
paint.setStrokeWidth(3);
Calendar calendar=Calendar.getInstance();
int currentMinute=calendar.get(Calendar.MINUTE);
int currentHour=calendar.get(Calendar.HOUR);
//计算分针和时针的角度
double minuteRadin=Math.toRadians((360-((currentMinute*6)-90))%360);
double hourRadin=Math.toRadians((360-((currentHour*30)-90))%360-(30*currentMinute/60));
//在表盘上画分针
canvas.drawLine(centerX, centerY, (int)(centerX+minuteSize*Math.cos(minuteRadin)),
(int)(centerY-hourSize*Math.sin(minuteRadin)), paint);
paint.setStrokeWidth(4);
paint.setColor(Color.RED);
//画时针
canvas.drawLine(centerX, centerY, (int)(centerX+hourSize*Math.cos(hourRadin)),
(int)(centerY-hourSize*Math.sin(hourRadin)), paint);
}
}
布局文件:
<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" >
<com.example.test.Clock
android:layout_width="match_parent"
android:layout_height="match_parent"
clockImageSrc="@drawable/ic_launcher"
scale="1.5"
centerWidthScale="0.5"
centerHeightScale="0.5"
minuteSize="100"
hourSize="30"
/>
</RelativeLayout>
在Activity中引用该布局文件即可显示自定义的时钟控件。