03
2017
03

安卓原生控件做时钟

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

效果图

时间的显示主要用到两个功能: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。


源码打包下载

« 上一篇下一篇 »

相关文章:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。