安卓原生控件做时钟
最近安卓开发中需要让一个图片旋转,需要做一个圆形的进度条。为了让测试不那么枯燥,做了一个时钟。
效果图

时间的显示主要用到两个功能:1、获取系统时间;2、旋转指针。
主类代码如下:
package com.example.androidtest2;
import java.util.Calendar;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
/**
* @author 作者:hanyeah
* @date 创建时间:2017-3-1 上午11:51:48
*/
public class MainActivity extends Activity {
private BiaopanView biaopan;
private BiaopanView progressView;
private ImageView shizhen;
private ImageView fenzhen;
private ImageView miaozhen;
private float x;
private float y;
private TextView tv;
public MainActivity() {
// TODO Auto-generated constructor stub
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.tv);
shizhen=(ImageView)findViewById(R.id.shizhen);
fenzhen=(ImageView)findViewById(R.id.fenzhen);
miaozhen=(ImageView)findViewById(R.id.miaozhen);
biaopan=(BiaopanView)findViewById(R.id.biaopan);
progressView=(BiaopanView)findViewById(R.id.biaopan);
biaopan.setOnClickListener(new View.OnClickListener() {
@SuppressLint("NewApi")
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
int w=v.getWidth();
int h=v.getHeight();
Log.d("hanyeah",String.format("w=%d,h=%d,x=%f,y=%f", w,h,x,y));
float angle=(float) Math.atan2(y-h/2,x-w/2);
tv.setText("角度:"+angle*180/Math.PI);
}
});
biaopan.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
x=event.getX();
y=event.getY();
return false;
}
});
hd.sendEmptyMessageDelayed(1, 1);
}
private Handler hd=new Handler(){
public void handleMessage(android.os.Message msg) {
updateBiaopan();
hd.sendEmptyMessageDelayed(1, 1000);
};
};
private float angle=0;
@SuppressLint("NewApi")
private void updateBiaopan(){
Calendar c = Calendar.getInstance();
int hour=c.get(Calendar.HOUR);
int minute=c.get(Calendar.MINUTE);
int secend=c.get(Calendar.SECOND);
shizhen.setRotation(hour*30+minute*30f/60f);
fenzhen.setRotation(minute*6);
miaozhen.setRotation(secend*6);
progressView.progress=secend*6;
progressView.invalidate();
}
}还多测试了一个功能,点击表盘,显示点击位置与表盘中心连线的角度(相对于哪个轴不重要,按需求映射就行)。
指针旋转实现起来太简单了,一个setRotation方法就可以了。具体实现起来可能需要一些技巧,有问题的话可以下载附件。
圆形的进度条(蓝色)是重写表盘的draw方法来实现的。
代码如下:
package com.example.androidtest2;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
/**
* @author 作者:hanyeah
* @date 创建时间:2017-3-1 下午4:43:09
*/
public class BiaopanView extends ImageView {
public BiaopanView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public BiaopanView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public BiaopanView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
super.draw(canvas);
//画笔。
Paint p = new Paint();
p.setAntiAlias(true);//平滑
p.setColor(Color.BLUE);// 设置红色
p.setStyle(Paint.Style.STROKE);//画线,不填充
p.setStrokeWidth(10);//线的粗细
//图片显示的宽高,根据布局计算,可能会变形
int w=this.getMeasuredWidth();
int h=this.getMeasuredHeight();
//默认宽高,即图片的实际尺寸。
int defaultW=661;
int defaultH=618;
float hw=defaultW/2;
float hh=defaultH/2;
//针的直径
int zhenW=536;
int hZhenW=zhenW/2;
int zhenH=526;
int hZhenH=zhenH/2;
canvas.save();
canvas.scale(w/(float)defaultW, h/(float)defaultH);
RectF oval1=new RectF(hw-hZhenW,hh-hZhenH,hw+hZhenW,hh+hZhenH);
canvas.drawArc(oval1, -90, progress, false, p);//小弧形
canvas.restore();
}
public float progress=0f;
}这里直接在显示表盘的类里面画进度条,而不是进度条自己占用一个显示控件,这样是有好处的。
具体可以参考源码,现在看来,实现的还是比较巧妙的。自己体会吧。
不一定要继承ImageView,继承View也行,由于我在xml布局中设置了src属性,所以用的ImageView。