自定义表盘,一个是关于canvas.rotate的运用,一个是关于Path,Math的运用

1.表盘一效果图

忽略小球上下移动。。。这个是重力感应下上下移动的。

本功能的主要实现是,三个背景圆圈的旋转。

首先,这三个圆需要无线旋转。

其次,需要根据不同的情况,加速,或者减速旋转。


不知道大家怎么想的,我最开始想到的就是利用,RotateAnimation,来实现旋转效果。new的时候,可以传入旋转的初始角度,和目的角度。setDuration(..),就实现了旋转的效果。


但是,android提供的这个旋转,从起始角度,到终点角度,在一定的时间范围呢,速度你是不可以控制的,什么时候旋转多块,都是不可控制的。这肯定不符合我们的需求。


而且,每次重新设置旋转时间的时候,都会有明显的卡顿。(重置嘛,整理好了重新开始旋转)。


后来使用了Canvas.rotate(旋转的度数,旋转中心x,旋转中心y)。相当于整个画板旋转。


核心思想,是在onDraw中,调用此方法。创建一个handler,每隔一段时间发送执行一次invalidate()方法。系统又会执行ondraw方法,就显示了既可以控制旋转速度,也可以无线旋转的效果。


package lenovo.com.keyguardtheme2;

import android.content.Context;
import android.graphics.Canvas;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;

/**
 * Created by Administrator on 2016/2/15.
 */
public class RotateImageView extends ImageView {

    private int measuredHeight;
    private int measuredWidth;
    private long old;
    private int mRotateTime = 18000;
    private int degreeTime;
    private int i = 0;
    private Handler handler;
    private Runnable runnable;
    private int mOrientation;

    public RotateImageView(Context context) {
        super(context);
    }

    public RotateImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        measuredHeight = this.getMeasuredHeight();
        measuredWidth = this.getMeasuredWidth();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        //左
        if(mOrientation == 0){
            canvas.rotate(i--, measuredWidth / 2, measuredHeight / 2);
        //右
        }else{
            canvas.rotate(i++, measuredWidth / 2, measuredHeight / 2);
        }

      super.onDraw(canvas);
    }

    //冲外部设置动画旋转的时间
    public void setRotateTime(int time){
        mRotateTime = time;
        degreeTime = mRotateTime / 360;
    }

    //开启旋转动画
    public void startRotateAnimation(){
        handler = new Handler();
        runnable = new Runnable() {
        @Override
        public void run() {
            invalidate();
            handler.postDelayed(this, degreeTime);
        }
    };
    handler.postDelayed(runnable, degreeTime);
    Log.i("qq","run.........................");
}

    //关闭动画
    public void finishAnimation(){
        if(handler!=null && runnable != null){
            handler.removeCallbacks(runnable);
        }

    }

    /**
     * 设置圆环的旋转方向
     * 0:left
     * 1:right
     */
    public void setRotateDirection(int orientation){
        mOrientation = orientation;
    }
}

2.表盘2 效果图

这张图大家看的可能不是太清楚。

一个表盘,北京是3个圆圈,分别代表时针,分针,秒针所对应的圆环。图片正中间显示当前的时间。

需求,就是随着时间的变化,显示由时针,分针,秒针所围成的三角形。


其实也很简单。

1.时针,分针,秒针,每转动一次旋转多少角度?

2.计算当前时间,对应的时分秒的角度。

3.根据角度,时分秒的半径,计算当前时分秒的针尖的坐标。

4.利用Path将其连接在一起。


提醒下自己,以前总觉得Math这个类用起来很方便,Math.sin(30);就算出角度是30的sin值了。。

后来才发现TM的是错误的。java要求你传入的是弧度值。

所以,如果要求30度对应的cos值,应该这么求

 Math.cos(Math.toRadians(degree))

<span style="font-size:18px;">package lenovo.com.keyguardtheme4;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

import java.util.Calendar;

/**
 * Created by Administrator on 2016/2/15.
 */
public class RotateImageViewWatch4 extends ImageView {

    private int measuredHeight;
    private int measuredWidth;
    private Context mContext;
    private Handler handler;
    private Runnable runnable;
    private int heightPixels;
    private int widthPixels;
    private Calendar calendar;

    /**
    * 时针
    */
    private int hourDegree = 30; //每秒旋转的度数
    private int currentHourDegree = 0;//当前旋转的度数
    /**
     * 分种
     */
    private int minuteDegree = 6; //每秒旋转的度数
    private int currentMinuteDegree = 0;//当前旋转的度数
    /**
     * 秒针
     */
    private int secondDegree = 6; //每秒旋转的度数
    private int currentSecondDegree = 0;//当前旋转的度数

    /**
     * 时针半径
     */
    private int hRadius = 134;
    /**
     * 分针半径
     */
    private int mRadius = 170;
    /**
     * 秒针半径
     */
    private int sRadius = 206;

    /**
     * 小时指针的坐标
     */
    private int[] h = new int[2];
    /**
     * 分针指针的坐标
     */
    private int[] m = new int[2];
    /**
     * 秒指针的坐标
     */
    private int[] s = new int[2];
    private Paint paint;
    private Path path;

    public RotateImageViewWatch4(Context context) {
        super(context);
        init(context);
    }

    public RotateImageViewWatch4(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {

        mContext = context;
        heightPixels = mContext.getResources().getDisplayMetrics().heightPixels;
        widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;

        paint = new Paint();

        paint.setColor( Color.argb(205, 00, 210, 255));
        paint.setAntiAlias(true);
        paint.setStrokeWidth(5.0f);
        paint.setStyle(Paint.Style.FILL);

        Log.i("2016.2.25", "屏幕的高度==" + heightPixels);
        Log.i("2016.2.25", "屏幕的宽度==" + widthPixels);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        measuredHeight = this.getMeasuredHeight();
        measuredWidth = this.getMeasuredWidth();

    }

    @Override
    protected void onDraw(Canvas canvas) {
      calculateDegree();

      super.onDraw(canvas);
        path = new Path();
        path.reset();
        path.moveTo(h[0],h[1]);
        path.lineTo(m[0],m[1]);
        path.lineTo(s[0],s[1]);
        path.close();
        canvas.drawPath(path,paint);
        Log.i("2016.2.25", "ondraw---------------------------");
        Log.i("2016.2.25", "h[0]=" + h[0] + " h[1]=" + h[1] + " m[0]="+m[0]
        +" m[1]="+m[1]+" s[0]="+s[0]+" s[1]="+s[1]);
    }

    /**
     * 当前时间
     */
    private int currentHour = 0;
    private int currentMinute = 0;
    private int currentSecond = 0;

    private void calculateDegree() {
        //每次将时间清零
        currentHour = 0;
        currentMinute = 0;
        currentSecond = 0;

        //当前时间
        calendar = Calendar.getInstance();
        currentHour = calendar.get(Calendar.HOUR);
        currentMinute = calendar.get(Calendar.MINUTE);
        currentSecond = calendar.get(Calendar.SECOND);

        //应该旋转的度数
        currentHourDegree = hourDegree * currentHour;
        currentMinuteDegree = minuteDegree * currentMinute;
        currentSecondDegree = secondDegree * currentSecond;

        //当前时针所在的坐标
        h = calcuateXY(hRadius,currentHourDegree);
        //当前分针所在的坐标
        m = calcuateXY(mRadius,currentMinuteDegree);
        //当前秒针所在的坐标
        s = calcuateXY(sRadius,currentSecondDegree);
        Log.i("2016.2.25","h[0]="+h[0]+" s[0]="+s[0]);
    }

    /**
     * 根据当前的旋转角度 计算半径与圆边交点所对应的x,y的值
     * @return
     */

    private int x,y;
    private int[] calcuateXY(int radius,int degree){
         int[] xy = new int[2];
        if(degree == 0){
           x = 0;
           y = radius;
           xy[0] = measuredWidth / 2;
           xy[1] = measuredHeight / 2 - radius;
        }else if(degree > 0 && degree <90){
           x = (int) (radius * Math.sin(Math.toRadians(degree)));
           y = (int) (radius * Math.cos(Math.toRadians(degree)));

           xy[0] = measuredWidth / 2 + x;
           xy[1] = measuredHeight / 2 - y;
        }else if(degree == 90){
           x = radius;
           y = 0;

           xy[0] = measuredWidth / 2 + radius;
           xy[1] = measuredHeight / 2 ;
        }else if(degree > 90 && degree < 180){
           degree = degree - 90;
           x =  (int) (radius * Math.cos(Math.toRadians(degree)));
           y = (int) (radius * Math.sin(Math.toRadians(degree)));

           xy[0] = measuredWidth / 2 + x;
           xy[1] = measuredHeight / 2 + y ;
        }else if(degree == 180){
           x = 0;
           y = radius;

           xy[0] = measuredWidth / 2;
           xy[1] = measuredHeight / 2 + radius ;
        }else if(degree > 180 && degree < 270){
           degree = degree - 180;
           x =  (int) (radius * Math.sin(Math.toRadians(degree)));
           y = (int) (radius * Math.cos(Math.toRadians(degree)));

            xy[0] = measuredWidth / 2 - x;
            xy[1] = measuredHeight / 2 + y ;
        }else if(degree == 270 ){
           x = radius;
           y = 0;

            xy[0] = measuredWidth / 2 - radius;
            xy[1] = measuredHeight / 2;
        }else if(degree > 270 && degree < 360){
           degree = degree - 270;
           x =  (int) (radius * Math.cos(Math.toRadians(degree)));
           y = (int) (radius * Math.sin(Math.toRadians(degree)));

           xy[0] = measuredWidth / 2 - x;
           xy[1] = measuredHeight / 2 -y ;
        }else if(degree == 360){
           x = 0;
           y = radius;

            xy[0] = measuredWidth / 2;
            xy[1] = measuredHeight / 2 - radius ;
        }
      //  Log.i("2016.2.25","x===="+x+"  y==="+y);
        Log.i("2016.2.25","xy[0]===="+xy[0]+"  xy[1]==="+xy[1]);
        return xy;
    }

    //开启旋转动画
    public void startRotateAnimation(){
        handler = new Handler();
        runnable = new Runnable() {
            @Override
            public void run() {
                invalidate();
                handler.postDelayed(this, 1000);
            }
        };
        handler.postDelayed(runnable, 1000);
        Log.i("qq","run.........................");
    }

    //关闭动画
    public void finishAnimation(){
        if(handler!=null && runnable != null){
            handler.removeCallbacks(runnable);
        }

    }
}</span>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值