Android自定义View---幸运大转盘

项目地址LargeTurntableApp

public class BigTurntableView extends View {
    private int bigTurntableView_bgColor = Color.parseColor("#ffff00");//转盘背景色
    private int bigTurntableView_selectRegionColor = Color.parseColor("#330000ff");//选中区域颜色

    private int bigTurntableView_lineColor = Color.parseColor("#ff0000");//分割线的颜色
    private int bigTurntableView_lineStrokeWidth = 2;//分割线的宽度

    private int bigTurntableView_arrowLineColor = Color.parseColor("#0000ff");//箭头线的颜色

    private int bigTurntableView_textSize = 50;//文字的字体大小
    private int bigTurntableView_textColor = Color.parseColor("#ff0000");//文字的颜色
    private String bigTurntableView_content = "";//aa|bb|cc 传入转盘文字数据

    private Paint mPaint;
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;
    private boolean isShowSelected = false;//是否展示选中的
    private boolean isUseTouchEvent = true;//触摸事件是否有效 默认有效
    private float avgDegree;//平均角度大小 根据内容自动计算
    private float rotateDegree;//旋转角度 默认第一条数据会在上方
    private String[] bisectionContent;//数据数组
    private volatile int contentIndex = 0;//当前选中内容下标


    public BigTurntableView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public void init(Context context, @Nullable AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BigTurntableView);
        bigTurntableView_bgColor = typedArray.getColor(R.styleable.BigTurntableView_bigTurntableView_bgColor, bigTurntableView_bgColor);
        bigTurntableView_selectRegionColor = typedArray.getColor(R.styleable.BigTurntableView_bigTurntableView_selectRegionColor, bigTurntableView_selectRegionColor);
        bigTurntableView_lineColor = typedArray.getColor(R.styleable.BigTurntableView_bigTurntableView_lineColor, bigTurntableView_lineColor);
        bigTurntableView_lineStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.BigTurntableView_bigTurntableView_lineStrokeWidth, bigTurntableView_lineStrokeWidth);
        bigTurntableView_arrowLineColor = typedArray.getColor(R.styleable.BigTurntableView_bigTurntableView_arrowLineColor, bigTurntableView_arrowLineColor);
        bigTurntableView_textSize = typedArray.getDimensionPixelSize(R.styleable.BigTurntableView_bigTurntableView_textSize, bigTurntableView_textSize);
        bigTurntableView_textColor = typedArray.getColor(R.styleable.BigTurntableView_bigTurntableView_textColor, bigTurntableView_textColor);
        bigTurntableView_content = typedArray.getString(R.styleable.BigTurntableView_bigTurntableView_content);
        if (TextUtils.isEmpty(bigTurntableView_content)) {
            bigTurntableView_content = "0|1|2|3|4|5";
        }
        bisectionContent = bigTurntableView_content.split("\\|");
        avgDegree = 360 / bisectionContent.length;
        rotateDegree = -avgDegree / 2;//默认选择角度
        mScroller = new Scroller(getContext(), new AccelerateDecelerateInterpolator());
        mPaint = new Paint();
        typedArray.recycle();
    }

    private int measuredWidth;
    private int measuredHeight;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measuredWidth = getMeasuredWidth();
        measuredHeight = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int cX = measuredWidth / 2;
        int cY = measuredHeight / 2;
        int cR = measuredHeight / 2;
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));//抗锯齿
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setStyle(Paint.Style.FILL);
        canvas.save();
        mPaint.setColor(bigTurntableView_bgColor);
        canvas.drawCircle(cX, cY, cR, mPaint);//画背景色
        canvas.restore();
        canvas.save();
        float selectBeginDegree;
        int offsetIndex = 0;
        if (rotateDegree <= 0) {
            offsetIndex = (int) -(Math.abs(rotateDegree) / avgDegree);
            contentIndex = (int) (Math.abs(rotateDegree) / avgDegree) % bisectionContent.length;
        } else {
            offsetIndex = (int) (Math.abs(rotateDegree) / avgDegree) + 1;
            contentIndex = (int) (Math.abs(rotateDegree) / avgDegree) % bisectionContent.length + 1;
            contentIndex = bisectionContent.length - contentIndex;
        }
        selectBeginDegree = rotateDegree - avgDegree * offsetIndex - avgDegree * bisectionContent.length / 4;
        if (isShowSelected) {
            mPaint.setColor(bigTurntableView_selectRegionColor);
            Path mPath = new Path();
            RectF rectF = new RectF(cX - cR, cY - cR, cX + cR, cY + cR);
            mPath.addArc(rectF, selectBeginDegree, avgDegree);
            mPath.lineTo(cX, cY);
            mPath.close();
            canvas.drawPath(mPath, mPaint);//画选中的扇形区域颜色
        }
        mPaint.setStrokeWidth(bigTurntableView_lineStrokeWidth);
        mPaint.setColor(bigTurntableView_lineColor);
        canvas.rotate(rotateDegree, cX, cY);
        for (int i = 0; i < bisectionContent.length; i++) {
            if (avgDegree == 360)
                break;
            canvas.drawLine(cX, 0, cX, cY, mPaint);//画区域线
            canvas.rotate(avgDegree, cX, cY);
        }
        canvas.rotate(avgDegree / 2, cX, cY);
        mPaint.setColor(bigTurntableView_textColor);
        for (int i = 0; i < bisectionContent.length; i++) {
            if (avgDegree == 360)
                break;
            mPaint.setTextSize(bigTurntableView_textSize);
            canvas.drawText(bisectionContent[i], cX - bisectionContent[i].length() * bigTurntableView_textSize / 2, cY / 2, mPaint);//画文字
            canvas.rotate(avgDegree, cX, cY);
        }
        canvas.restore();
        canvas.save();
        mPaint.setColor(bigTurntableView_arrowLineColor);
        mPaint.setStrokeWidth(bigTurntableView_lineStrokeWidth * 2);
        canvas.drawLine(cX, 0, cX, cY, mPaint);
        canvas.drawLine(cX, 0, cX - 25, 25, mPaint);
        canvas.drawLine(cX, 0, cX + 25, 25, mPaint);//画箭头
        canvas.restore();
    }

    private float lastX = 0f;
    private float lastY = 0f;
    private float disX, disY;
    private boolean isAllowShowSelected = false;//初始化时不允许展示选中

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isUseTouchEvent)
            return super.onTouchEvent(event);
        float viewX = event.getX();
        float viewY = event.getY();
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                isAllowShowSelected = true;
                mScroller.forceFinished(true);
                addVelocityTracker(event);
                lastX = viewX;
                lastY = viewY;
                break;
            case MotionEvent.ACTION_MOVE:
                hideSelected();
                isAllowShowSelected = false;
                addVelocityTracker(event);
                disX = viewX - lastX;
                disY = viewY - lastY;
                lastX = viewX;
                lastY = viewY;
                rotateDegree = (int) (rotateDegree + disY);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // 在触点抬起后再继续滑动一定距离
                int xVelocity = getXScrollVelocity();
                int yVelocity = getYScrollVelocity();
                mScroller.fling(0, lastScrollCurrY, (int) (xVelocity), (int) (yVelocity), -Integer.MIN_VALUE, Integer.MAX_VALUE, -Integer.MIN_VALUE, Integer.MAX_VALUE);
                invalidate();
                recycleVelocityTracker();
                break;
        }
        return true;
    }


    private int lastScrollCurrY = 0;
    private int computeScrollDistance = 0;

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            computeScrollDistance = mScroller.getCurrY() - lastScrollCurrY;
            lastScrollCurrY = mScroller.getCurrY();
            rotateDegree = (int) (rotateDegree + computeScrollDistance);
            if (mScroller.isFinished()) {
                isShowSelected = true;
                isAllowShowSelected = true;
            }
            if (!isAllowShowSelected) {
                invalidate();
            }
        }
        if (isAllowShowSelected) {
            showSelected();
            if (onSelectedListener != null) {
                onSelectedListener.onSelected(Math.abs(contentIndex), getBisectionContent());
            }
            isAllowShowSelected = false;
        }

    }

    /**
     * 添加用户的速度跟踪器
     */
    private void addVelocityTracker(MotionEvent event) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
    }

    /**
     * 移除用户速度跟踪器
     */
    private void recycleVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    /**
     * 获取X方向的滑动速度,大于0向右滑动,反之向左
     */
    private int getXScrollVelocity() {
        mVelocityTracker.computeCurrentVelocity(500);
        int velocity = (int) mVelocityTracker.getXVelocity();
        return velocity;
    }

    /**
     * 获取Y方向的滑动速度,大于0向下滑动,反之向上
     */
    private int getYScrollVelocity() {
        mVelocityTracker.computeCurrentVelocity(500);
        int velocity = (int) mVelocityTracker.getYVelocity();
        return velocity;
    }

    private void showSelected() {
        isShowSelected = true;
        invalidate();
    }

    private void hideSelected() {
        isShowSelected = false;
        invalidate();
    }

    //自动选择一次
    public void startAutoSelect(OnSelectedListener onSelectedListener) {
        this.onSelectedListener = onSelectedListener;
        post(new Runnable() {
            @Override
            public void run() {
                hideSelected();
                int dis = (int) ((Math.random()) * 1000 + 1000);
                mScroller.startScroll(0, lastScrollCurrY, 0, dis, 1000 * 3);
                invalidate();
            }
        });
    }

    public void setBigTurntableView_bgColor(int bigTurntableView_bgColor) {
        this.bigTurntableView_bgColor = bigTurntableView_bgColor;
        invalidate();
    }

    public void setBigTurntableView_selectRegionColor(int bigTurntableView_selectRegionColor) {
        this.bigTurntableView_selectRegionColor = bigTurntableView_selectRegionColor;
        invalidate();
    }

    public void setBigTurntableView_lineColor(int bigTurntableView_lineColor) {
        this.bigTurntableView_lineColor = bigTurntableView_lineColor;
        invalidate();
    }

    public void setBigTurntableView_lineStrokeWidth(int bigTurntableView_lineStrokeWidth) {
        this.bigTurntableView_lineStrokeWidth = bigTurntableView_lineStrokeWidth;
    }

    public void setBigTurntableView_arrowLineColor(int bigTurntableView_arrowLineColor) {
        this.bigTurntableView_arrowLineColor = bigTurntableView_arrowLineColor;
        invalidate();
    }

    public void setBigTurntableView_textSize(int bigTurntableView_textSize) {
        this.bigTurntableView_textSize = bigTurntableView_textSize;
        invalidate();
    }

    public void setBigTurntableView_textColor(int bigTurntableView_textColor) {
        this.bigTurntableView_textColor = bigTurntableView_textColor;
        invalidate();
    }

    public void setBigTurntableView_content(String bigTurntableView_content) {
        this.bigTurntableView_content = bigTurntableView_content;
        invalidate();
    }

    //设置触摸事件是否有效
    public void setUseTouchEvent(boolean useTouchEvent) {
        isUseTouchEvent = useTouchEvent;
    }

    public String[] getBisectionContent() {
        return bisectionContent;
    }

    private OnSelectedListener onSelectedListener;

    public interface OnSelectedListener {
        void onSelected(int posion, String[] bisectionContent);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--大转盘-->
    <declare-styleable name="BigTurntableView">
        <attr name="bigTurntableView_bgColor" format="color" /><!--转盘背景色-->
        <attr name="bigTurntableView_selectRegionColor" format="color" /><!--选中区域颜色-->

        <attr name="bigTurntableView_lineColor" format="color" /><!--分割线的颜色-->
        <attr name="bigTurntableView_lineStrokeWidth" format="dimension" /><!--分割线的宽度-->

        <attr name="bigTurntableView_arrowLineColor" format="color" /><!--箭头线的颜色-->

        <attr name="bigTurntableView_textSize" format="dimension" /><!--文字的字体大小-->
        <attr name="bigTurntableView_textColor" format="color" /><!--文字的颜色-->

        <attr name="bigTurntableView_content" format="string" /><!--aa|bb|cc 传入转盘文字数据-->

    </declare-styleable>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.dxh.myapplication.widget.BigTurntableView
        android:id="@+id/bigTurntableView"
        android:layout_width="wrap_content"
        android:layout_height="400dp"
        app:bigTurntableView_arrowLineColor="#0000ff"
        app:bigTurntableView_bgColor="#00ff00"
        app:bigTurntableView_content="面|饼|汤菜|米饭|混沌|饺子|减肥|睡觉"
        app:bigTurntableView_lineColor="#ff0000"
        app:bigTurntableView_lineStrokeWidth="2px"
        app:bigTurntableView_selectRegionColor="#330000ff"
        app:bigTurntableView_textColor="#ff0000"
        app:bigTurntableView_textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_autoSelect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="自动选择一次"
        app:layout_constraintTop_toBottomOf="@+id/bigTurntableView" />
</androidx.constraintlayout.widget.ConstraintLayout>
        bigTurntableView.setUseTouchEvent(false);//设置触摸事件是否有效
        btnAutoSelect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //开启自动选择
                bigTurntableView.startAutoSelect(new BigTurntableView.OnSelectedListener() {
                    @Override
                    public void onSelected(int posion, String[] bisectionContent) {
                        Toast.makeText(MainActivity.this, bisectionContent[posion], Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });

效果图

1.gif
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容