自定义时间选择器

这里是源码地址:http://download.csdn.net/detail/h55l55/9521851

首先简单介绍一下这个选择器,可以旋转表针的方式旋转选择时间,然后在下一个视图中选择分钟数。通过两个接口回调来返回选择的结果。接下来说一下编程思路:

1、确定需要的颜色常量,以及可以改变值得常量
    /**
     * 默认外圆半径
     */
    private final static int DEFAULT_OUT_RADIO = 100;
    /**
     * 默认选择小圆的半径
     */
    private final static int DEFAULT_CHECK_RAIDO_WIDTH = 20;
    /**
     * 外部文字未选中颜色
     */
    private final static int DEFAULT_OUT_TEXT_UNCHECKED_COLOR = 0xff1f1f1f;
    /**
     * 内部文字未选中颜色
     */
    private final static int DEFAULT_IN_TEXT_UNCHECKED_COLOR = 0xff6d6d6d;
    /**
     * 外部文字选中颜色
     */
    private final static int DEFAULT_OUT_TEXT_CHECKED_COLOR = 0xffffffff;
    /**
     * 内部文字选中颜色
     */
    private final static int DEFAULT_IN_TEXT_CHECKED_COLOR = 0xffffffff;
    /**
     * 连接线条颜色
     */
    private final static int DEFAULT_LINE_COLOR = 0xffff6633;
    /**
     * 外部文字大小
     */
    private final static int DEFAULT_OUT_TEXT_SIZE = 14;
    /**
     * 内部文字大小
     */
    private final static int DEFAULT_IN_TEXT_SIZE = 10;
    /**
     * 时间改变监听器
     */
    private onHourChangedListener listener;
    /** 选中时候圆圈的半径 */
    private int checkCircleRadio;
    /** 未选中外部文字颜色 */
    private int mOutUnCheckedColor;
    /** 未选中内部文字颜色 */
    private int mInUncheckedColor;
    /** 外部选中文字颜色 */
    private int mOutTextCheckedColor;
    /** 外部选中文字颜色 */
    private int mInTextCheckedColor;
    /** 线的颜色 */
    private int mLineColor;
    /** 外部文字大小 */
    private int mOutTextSize;
    /** 内部文字大小 */
    private int mInTextSize;
    /** 画表盘数字的画笔 */
    private Paint mTextPaint = new Paint();;
    /** 外面圆的半径 */
    private int mOutRadius;
    /** 内部圆的半径 */
    private int mInRadius;
    /** 单前选中的小时数 */
    private Integer hours;
    /** 当前视图的宽度 */
    private int mViewWight;  
2、初始化画笔的值

在此之前需要重写构造方法,然后在构造方法中调动此方法。

    /** 给变量赋值,可以使用自定义属性 */
    private void init() {
        mOutUnCheckedColor = DEFAULT_OUT_TEXT_UNCHECKED_COLOR;
        mInUncheckedColor = DEFAULT_IN_TEXT_UNCHECKED_COLOR;
        mOutTextCheckedColor = DEFAULT_OUT_TEXT_CHECKED_COLOR;
        mLineColor = DEFAULT_LINE_COLOR;
        mOutTextSize = sp2px(getContext(), DEFAULT_OUT_TEXT_SIZE);
        mInTextCheckedColor = DEFAULT_IN_TEXT_CHECKED_COLOR;
        mInTextSize = sp2px(getContext(), DEFAULT_IN_TEXT_SIZE);
        mOutRadius = dp2px(getContext(), DEFAULT_OUT_RADIO);
        checkCircleRadio = dp2px(getContext(), DEFAULT_CHECK_RAIDO_WIDTH);
        mInRadius = mOutRadius - 3 * mOutTextSize;
    }  
3、在Ondraw中开始绘制选择圈

在onDraw中调用画圈和画数字的方法

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.translate(mViewWight / 2, mViewWight / 2);
        drawCircle(canvas);
        drawNumber(canvas);
    }  

画圈的方法,用来绘制表的指针和选中后的圆圈

    /** 画选数字的圆圈 */
    private void drawCircle(Canvas canvas) {
        mTextPaint.setTextSize(mOutTextSize);
        if (hours > 12 || hours == 0) {// 13点到00点
            mTextPaint.setColor(mLineColor);
            mTextPaint.setStrokeWidth(checkCircleRadio / 20);
            Point point = getPoint(hours * 30, mInRadius);
            int y = point.y;
            canvas.drawCircle(point.x, y, checkCircleRadio, mTextPaint);
            canvas.drawLine(0, 0, point.x, y, mTextPaint);
        } else {// 1到12点
            mTextPaint.setColor(mLineColor);
            Point point = getPoint(hours * 30, mOutRadius);
            int y = point.y;
            canvas.drawCircle(point.x, y, checkCircleRadio, mTextPaint);
            canvas.drawLine(0, 0, point.x, y, mTextPaint);
        }
        canvas.drawCircle(0, 0, checkCircleRadio / 10, mTextPaint);
    }  
4、在ondraw中开始绘制数字表盘

画表盘的方法,用来绘制选择时候的数字

    /** 画数字表盘 */
    private void drawNumber(Canvas canvas) {
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextSize(mOutTextSize);
        // 所绘制文字宽高
        int textWight;
        for (int i = 1; i < 13; i++) {
            if (hours == i) {
                mTextPaint.setColor(mOutTextCheckedColor);
            } else {
                mTextPaint.setColor(mOutUnCheckedColor);
            }
            textWight = (int) mTextPaint.measureText(i + "");
            Point point = getPoint(i * 30, mOutRadius);
            canvas.drawText(i + "", point.x - textWight / 2, 
                    point.y + mOutTextSize / 2, mTextPaint);
        }
        mTextPaint.setTextSize(mInTextSize);
        for (int i = 13; i < 25; i++) {
            if (hours == i) {
                mTextPaint.setColor(mInTextCheckedColor);
            } else {
                mTextPaint.setColor(mInUncheckedColor);
            }
            textWight = (int) mTextPaint.measureText("00");
            String text = i + "";
            if (i == 24) {
                text = "00";
                if (hours == 0) {
                    mTextPaint.setColor(mInTextCheckedColor);
                }
            }
            Point point = getPoint((i - 12) * 30, mInRadius);
            canvas.drawText(text, point.x - textWight / 2,
                     point.y + mInTextSize / 2, mTextPaint);
        }
    }  

getPoint方法,用来获取当前旋转角度下的坐标

    /** 获取在角度为degree,半径为radio时候点的坐标 */
    private Point getPoint(int degree, int radio) {
        int y = (int) (-Math.cos(2 * Math.PI / 360 * degree) * radio);
        int x = (int) (Math.sin(2 * Math.PI / 360 * degree) * radio);
        return new Point(x, y);
    }  
5、重写onTouchEvent方法,获取手指的坐标,然后重新绘制,使圆圈移动到指定位置

重写onTouchEvent方法

    /** 监听触摸事件 */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            hours = getTouchHours(event.getX(), event.getY());
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            // 获取属于哪个时间点
            // 更改时间属性
            hours = getTouchHours(event.getX(), event.getY());
            // 重绘
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            if (hours < 13) {
                Toast.makeText(getContext(), hours + "", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getContext(), hours + "", Toast.LENGTH_SHORT).show();
            }
            if (null != listener) {
                listener.onHourChanged(hours, true);
            }
            break;
        }
        return true;
    }  

获取当前点击位置对应的时间

    /** 获取当前触摸点对应的小时值 */
    private int getTouchHours(float x, float y) {
        x = x - mViewWight / 2;
        y = y - mViewWight / 2;
        for (int i = 0; i < 360; i += 30) {
            if (isInOutCircle(i, x, y)) {
                if (i == 0) {
                    return 12;
                }
                return i / 30;
            }
            if (isInInnerCircle(i, x, y)) {
                return 12 + i / 30 == 12 ? 0 : 12 + i / 30;
            }
        }
        return hours;
    }  

判断当前点击位置是否位于指定的时间处

    /** 坐标是否落在外部圆上 */
    private boolean isInOutCircle(int angle, float x, float y) {
        // DateUtils.getDayOfWeekString(Calendar.MONDAY, abbrev)
        // 获取x坐标的范围
        int xx = (int) ((Math.sin(2 * Math.PI / 360 * angle)) * mOutRadius);
        int yy = -(int) ((Math.cos(2 * Math.PI / 360 * angle)) * mOutRadius);
        // (0,-1440)
        // xx-textHeight<x<xx+textHeight
        if (x < xx - checkCircleRadio || x > xx + checkCircleRadio) {
            return false;
        }
        if (yy > 0) {
            if (y < yy - checkCircleRadio || y > yy) {
                return false;
            }
        } else {
            if (y < yy || y > yy + checkCircleRadio) {
                return false;
            }
        }
        return true;
    }
    /** 坐标是否落在内部圆上 */
    private boolean isInInnerCircle(int angle, float x, float y) {
        // 获取x坐标的范围
        int xx = (int) ((Math.sin(2 * Math.PI / 360 * angle)) * mInRadius);
        int yy = -(int) ((Math.cos(2 * Math.PI / 360 * angle)) * mInRadius);
        // xx-textHeight<x<xx+textHeight
        if (x < xx - checkCircleRadio || x > xx + checkCircleRadio) {
            return false;
        }
        if (yy > 0) {
            if (y < yy - checkCircleRadio || y > yy) {
                return false;
            }
        } else {
            if (y < yy || y > yy + checkCircleRadio) {
                return false;
            }
        }
        return true;
    }  
6、在手指抬起时候回调接口方法,把选择的时间传递出去
    /** 设置时间回调监听器 */
    public void setOnHourChangedListener(onHourChangedListener listener) {
        this.listener = listener;
    }
    /** 当时间改变时候回调 */
    interface onHourChangedListener {
        void onHourChanged(int hour, boolean isUp);
    }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值