一个可跟随手指移动的view

效果:...

package com.diandou.demo41_cycle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by baiya on 2018/2/26.
 */

public class CycleView extends View {

    /** 当前控件的宽 */
    private int mWidthSize = 1000;
    /** 当前控件的高 */
    private int mHeightSize = 1000;

    int zhouqi = 28;

    private static final String TAG = "CycleView";
    private Path mCyclePath;
    private Paint mCyclePaint;
    private TextPaint mTextPaint;
    private PathMeasure mPathMeasure;
    private int ox;
    private int oy;
    private int radius;
    private float mWheelCurX;
    private float mWheelCurY;
    private float mAngle;
    private int mCurrentProcess;

    public CycleView(Context context) {
        this(context, null);
    }

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

    /**
     * 初始化
     * @param context
     * @param attrs
     */
    private void init(Context context, AttributeSet attrs) {
        mCyclePaint = new Paint();
        mCyclePaint.setColor(Color.WHITE);
        mCyclePaint.setStrokeWidth(10);
        mCyclePaint.setStyle(Paint.Style.STROKE);


        /** 文字画笔 */
        mTextPaint = new TextPaint();
        mTextPaint.setColor(Color.BLACK);
        mTextPaint.setStrokeWidth(2);
        mTextPaint.setStyle(Paint.Style.FILL);/** 这个也有问题 */
        mTextPaint.setTextSize(30);/** 文字大小, 文字的大小是按像素的 */
        /**
         * 设置文字的偏移量
         * 文字的偏移量默认是left 就是 文本 左下角 的坐标点....
         * */
        mTextPaint.setTextAlign(Paint.Align.LEFT);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//        Log.d(TAG, "onMeasure" + " widthSize--" + widthSize + " heightSize--" + heightSize);
        int measuredHeight, measuredWidth;
        if (widthMode == MeasureSpec.EXACTLY){
            measuredWidth = widthSize;
        } else {
            //如果能用到这种情况, 那就是不确定大小咯
            measuredWidth = mHeightSize;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            measuredHeight = heightSize;
        } else {
            measuredHeight = mHeightSize;
        }
        setMeasuredDimension(measuredWidth, measuredHeight);
        mHeightSize = getMeasuredHeight();
        mWidthSize = getMeasuredWidth();
        ox = mWidthSize/2;
        oy = mHeightSize/2;
        radius = (mWidthSize -200)/2;
        mCyclePath = new Path();
        RectF rectF = new RectF(100, 100, mWidthSize-100, mHeightSize-100);

        mCyclePath.addArc(rectF, 270, 359);
        mPathMeasure = new PathMeasure(mCyclePath, false);


    }

    @Override
    protected void onDraw(Canvas canvas) {

        // 画中心圆..

        // 画圆周边的小圆

        // 写中间的文字

        // 还有可滑动覆盖的圆

        canvas.drawPath(mCyclePath, mCyclePaint);
        for (int i = 0; i < zhouqi; i++) {
            float[] coords = {0f, 0f};
            String s = i+"";

            mPathMeasure.getPosTan(i * mPathMeasure.getLength() / zhouqi, coords, null);
            canvas.drawCircle(coords[0], coords[1], 30, mCyclePaint);
//            canvas.drawText(i+"", coords[0]-15, coords[1]+15, mTextPaint);
            Rect bounds = new Rect();
            mTextPaint.getTextBounds(s, 0, s.length(), bounds);
            Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();

            int baseline = (int) (coords[1] - fontMetrics.bottom/2 - fontMetrics.top/2);

            canvas.drawText(s,coords[0] - bounds.width() / 2, baseline, mTextPaint);
        }

        if (mWheelCurX != 0 && mWheelCurY != 0) {
            canvas.drawCircle(mWheelCurX, mWheelCurY, 100, mCyclePaint);
        } else {
            refershPosition();
            invalidate();
        }






    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
//        Log.d(TAG, "x---" + x);
//        Log.d(TAG, "y---" + y);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                /** 拿到x, y的值后, 计算 */
                break;
            case MotionEvent.ACTION_MOVE:
                float cos = getCos(x, y, ox, oy);
                if (x < getWidth() / 2) { // 滑动超过180度
                    mAngle = (float) (180 + Math.acos(cos) * 180 / Math.PI);
                } else { // 没有超过180度
                    mAngle = (float) (180 - Math.acos(cos) * 180 / Math.PI);
                }
                refershSmallCyclePosition(cos);
                mCurrentProcess = (int) (mAngle / 360 * 28 + 0.5);
                Log.d(TAG, "mCurrentProcess---" + mCurrentProcess);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                //当手指up的时候
                //需要定位到那一点上
                int angle = mCurrentProcess * 360/28;
                Log.d(TAG, "y---" + y);
                refershSmallCyclePosition(-Math.cos(Math.toRadians(angle)));
                invalidate();
                break;
            case MotionEvent.ACTION_CANCEL:
                int angle1 = mCurrentProcess * 360 /28;
                refershSmallCyclePosition(-Math.cos(Math.toRadians(angle1)));
                invalidate();
                break;
        }

        /** 拿到点击事件后, 不再向上传递了 */
        return true;
    }


    /**
     * 更具选的position来刷新小圆的位置
     */
    private void refershPosition() {
        mAngle = (float) (1 / 28 * 360.0);
        double cos = -Math.cos(Math.toRadians(mAngle));
        refershSmallCyclePosition(cos);
    }

    /**
     * 重置小圆点的位置
     * @param cos
     */
    private void refershSmallCyclePosition(double cos) {
        /** 小圆点坐标 */
        if (mAngle < 180) {
            mWheelCurX = (float) (ox + Math.sqrt(1 - cos * cos) * radius);
        } else {
            mWheelCurX = (float) (ox - Math.sqrt(1 - cos * cos) * radius);
        }
        mWheelCurY = (int) (getMeasuredHeight() / 2 + radius * (float) cos);
    }


    /**
     * 获取倾斜的cos的值
     * @param x 手指按下点的x坐标
     * @param y 手指按下点的y坐标
     * @param ox 圆点x坐标
     * @param oy 圆点y坐标
     * @return 返回手指按下的点, 相对于圆心的度数
     */
    public float getCos(float x, float y, int ox, int oy) {
        float width = x - ox;
        float height = y - oy;
        float slope = (float) Math.sqrt(width * width + height * height);
        float cos = height / slope;
        return cos;
    }





}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值