可以惯性滑动的半圆转盘,圆形菜单。


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;

import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import java.util.ArrayList;

public class PieView extends View {
    private Paint viewPaint;//画扇形和中间圆的画笔

    private Paint textPaint;//文字画笔

    private ArrayList<String> itemList = new ArrayList<>();


    private int weith;//宽
    private int height;//高

    private float maxAngle;//最大的滑动角度
    private Context mContext;
    private float angleCha;
    private String mainText = "我的空间";

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

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

    public PieView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        this.mContext = context;
        viewPaint = new Paint();
        viewPaint.setAntiAlias(true);
        viewPaint.setStyle(Paint.Style.FILL);
        viewPaint.setColor(Color.GREEN);

        textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(sp2px(18));
        textPaint.setTextAlign(Paint.Align.CENTER);

        itemList.clear();
        itemList.add("外婆家1");
        itemList.add("老家2");
        itemList.add("奶奶家3");
        itemList.add("好多家4");
        itemList.add("外婆家5");
        itemList.add("老家6");

        itemList.add("奶奶家7");
        itemList.add("好多家8");
        itemList.add("姥姥家9");
        itemList.add("姥姥家10");
        itemList.add("姥姥家11");
        itemList.add("姥姥家12");

        itemList.add("我家13");
        itemList.add("我家14");
        itemList.add("我家15");
        itemList.add("我家16");
        itemList.add("我家17");
        itemList.add("我家18");

        itemList.add(". . .");

        maxAngle = -30 * (itemList.size() - 6);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        weith = widthSize;
        height = weith / 2;
        //应用测量值
        setMeasuredDimension(weith, height);
    }

    private int[] angle;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
       

        angle = new int[itemList.size()];
        for (int i = 0; i < itemList.size(); i++) {
            angle[i] = -75 + 30 * i + (int) recentAcgle;
        }

        for (int i = 0; i < angle.length; i++) {
            if (angle[i] > -105 && angle[i] < 105) {
                canvas.save();
                canvas.rotate(angle[i], weith / 2, height);
                RectF rectF;
                if (clickItem == i) {
                    rectF = new RectF(0, dp2px(5), weith, height * 2 - dp2px(5));
                    viewPaint.setColor(Color.parseColor("#058586"));
                } else {
                    rectF = new RectF(0, 0, weith, height * 2);
                    viewPaint.setColor(Color.parseColor("#02fcfd"));
                }

                canvas.drawArc(rectF, 255, 29, true, viewPaint);
                textPaint.setTextSize(sp2px(18));
                canvas.drawText(itemList.get(i), weith / 2, height / 6, textPaint);
                canvas.restore();
            }

        }

        viewPaint.setColor(Color.WHITE);
        RectF rectSmall = new RectF(weith / 6, height / 3, weith * 5 / 6, height * 5 / 3);
        canvas.drawArc(rectSmall, 180, 180, true, viewPaint);


        RectF rectCenter;
        if (clickItem == itemList.size()) {
            viewPaint.setColor(Color.parseColor("#058586"));
            rectCenter = new RectF(weith / 4 + dp2px(5), height / 2 + dp2px(5), weith * 3 / 4 - dp2px(5), height * 3 / 2 - dp2px(5));
        } else {
            viewPaint.setColor(Color.parseColor("#02fcfd"));
            rectCenter = new RectF(weith / 4, height / 2, weith * 3 / 4, height * 3 / 2);
        }

        canvas.drawArc(rectCenter, 180, 180, true, viewPaint);

        textPaint.setTextSize(sp2px(25));
        canvas.drawText(mainText, weith / 2, height - textPaint.getTextSize(), textPaint);

    }

    float downX = 0;
    float downY = 0;

    private float recentAcgle;


    private float clickAcgle = 0;//当前点击的角度,用于确定当前点击在哪个item中。

    private int clickItem = -1;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                viewRuning = false;
                mHandler.removeMessages(1);
                mHandler.removeMessages(0);

                downX = event.getX();
                downY = event.getY();

                angleCha = 0;
                clickAcgle = calcAngle(event.getX(), event.getY()) - 255;


                double sqrt = Math.sqrt((downX - weith / 2) * (downX - weith / 2) + (downY - height) * (downY - height));
                if (sqrt <= weith / 2 && sqrt >= weith / 3) {
                    for (int i = 0; i < angle.length; i++) {
                        if (angle[i] < clickAcgle && angle[i] + 30 > clickAcgle) {
                            clickItem = i;
                            break;
                        }
                    }
                } else if (sqrt <= weith / 4) {
                    clickItem = itemList.size();
                }

                mHandler.sendEmptyMessageDelayed(1, 200);

                Log.e("onTouchEvent_DOWN", "clickAcgle : " + clickAcgle + " clickItem : " + clickItem);

                break;
            case MotionEvent.ACTION_MOVE:

                angleCha = calcAngle(event.getX(), event.getY()) - calcAngle(downX, downY);
                downY = event.getY();
                downX = event.getX();
                Log.e("onTouchEvent_MOVE", "angleCha : " + angleCha + " clickItem : " + clickItem);

                if (Math.abs(angleCha)>=1 &&clickItem >= 0) {
                    clickItem = -1;
                    mHandler.removeMessages(1);
                }

                // 防止越界
                if (angleCha < -300) {
                    angleCha = angleCha + 360;
                } else if (angleCha > 300) {
                    angleCha = angleCha - 360;
                }
                recentAcgle += angleCha;
                if (itemList.size() <= 6) {
                    if (recentAcgle <= 0) {
                        recentAcgle = 0;
                    } else if (recentAcgle >= maxAngle) {
                        recentAcgle = maxAngle;
                    }
                } else {
                    if (recentAcgle > 0) {
                        recentAcgle = 0;
                    } else if (recentAcgle < maxAngle) {
                        recentAcgle = maxAngle;
                    }
                }
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                Log.w("onTouchEvent_UP", "angleCha : " + angleCha);
                clickAcgle = calcAngle(event.getX(), event.getY()) - 255;
                for (int i = 0; i < angle.length; i++) {

                    Log.w("onTouchEvent_UP", "点击的事件 : "+i +(angle[i] < clickAcgle && angle[i] + 30 > clickAcgle));
                    if (angle[i] < clickAcgle && angle[i] + 30 > clickAcgle) {
                        Log.w("onTouchEvent_UP", (clickItem == i)+"........点击的事件 : " + clickItem);
                        if (clickItem == i) {
                            Log.w("onTouchEvent_UP", (listener != null)+"点击的事件 : " + clickItem);
                            if (listener != null) {
                                listener.ItemClick(clickItem);
                            }
                        }
                        break;
                    }
                }
                if (clickItem == itemList.size()) {
                    if (listener != null) {
                        listener.MainClick();
                    }
                }
                clickItem = -1;
                invalidate();
                if (itemList.size() > 6 && Math.abs(angleCha) > 1) {
                    new myThread().start();
                }
                break;
            case MotionEvent.ACTION_CANCEL:

                break;
        }


        return true;
    }


    private boolean viewRuning;//

    private class myThread extends Thread {
        private int time;//时间
        private int space;//速度

        public myThread() {
            viewRuning = true;
        }

        @Override
        public void run() {
            super.run();

            int i = 0;
            while (viewRuning) {
                recentAcgle += (float) (angleCha * accelerateItp[i]);
                if (recentAcgle >= 0) {
                    recentAcgle = 0;
                    viewRuning = false;
                    break;
                }
                if (recentAcgle <= maxAngle) {
                    recentAcgle = maxAngle;
                    viewRuning = false;
                    break;
                }
                i++;

                Log.w("myThread", "handleMessage : " + i + " viewRuning : " + Thread.currentThread().getName());
                if (viewRuning) {
                    mHandler.sendEmptyMessage(0);
                    SystemClock.sleep(10);
                }

                if (i >= 100) {
                    viewRuning = false;
                }
            }
        }
    }


    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.e("onTouchEvent_mHandler", "handleMessage : " + clickAcgle + " viewRuning : " + viewRuning);

            if (msg.what == 0) {

                PieView.this.invalidate();
            } else if (msg.what == 1) {
                PieView.this.invalidate();
            }
        }
    };

    /**
     * 设置数据
     */
    public void setData(ArrayList list, String strText) {
        this.mainText = strText;
        itemList.clear();
        itemList.addAll(list);
        recentAcgle = 0;
        PieView.this.invalidate();

    }

    /**
     * 数据根据AccelerateDecelerateInterpolator插值器的减速算法得到
     * <p>
     * public float getInterpolation(float input) {
     * return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
     * }
     */
    private double[] accelerateItp = {1.0000, 0.9998, 0.9990, 0.9978, 0.9961, 0.9938, 0.9911, 0.9880, 0.9843, 0.9801, 0.9755, 0.9704, 0.9649, 0.9589, 0.9524, 0.9455, 0.9382, 0.9304, 0.9222, 0.9135, 0.9045, 0.8951, 0.8853, 0.8751, 0.8645, 0.8536, 0.8423, 0.8307, 0.8187, 0.8065, 0.7939, 0.7810, 0.7679, 0.7545, 0.7409, 0.7270, 0.7129, 0.6986, 0.6841, 0.6694, 0.6545, 0.6395, 0.6243, 0.6091, 0.5937, 0.5782, 0.5627, 0.5471, 0.5314, 0.5157, 0.5000, 0.4843, 0.4686, 0.4529, 0.4373, 0.4218, 0.4063, 0.3909, 0.3757, 0.3605, 0.3455, 0.3306, 0.3159, 0.3014, 0.2871, 0.2730, 0.2591, 0.2455, 0.2321, 0.2190, 0.2061, 0.1935, 0.1813, 0.1693, 0.1577, 0.1464, 0.1355, 0.1249, 0.1147, 0.1049, 0.0955, 0.0865, 0.0778, 0.0696, 0.0618, 0.0545, 0.0476, 0.0411, 0.0351, 0.0296, 0.0245, 0.0199, 0.0157, 0.0120, 0.0089, 0.0062, 0.0039, 0.0022, 0.0010, 0.0002};

    /**
     * 以按钮圆心为坐标圆点,建立坐标系,求出(targetX, targetY)坐标与x轴的夹角
     *
     * @param targetX x坐标
     * @param targetY y坐标
     * @return (targetX, targetY)坐标与x轴的夹角
     */
    private float calcAngle(float targetX, float targetY) {
        float x = targetX - weith / 2;//len/2 圆点x坐标
        float y = targetY - height;//len/2 圆点y坐标
        double radian;

        if (x != 0) {
            float tan = Math.abs(y / x);
            if (x > 0) {
                if (y >= 0) {
                    radian = Math.atan(tan);
                } else {
                    radian = 2 * Math.PI - Math.atan(tan);
                }
            } else {
                if (y >= 0) {
                    radian = Math.PI - Math.atan(tan);
                } else {
                    radian = Math.PI + Math.atan(tan);
                }
            }
        } else {
            if (y > 0) {
                radian = Math.PI / 2;
            } else {
                radian = -Math.PI / 2;
            }
        }
        return (float) ((radian * 180) / Math.PI);
    }

    private int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dp, getResources().getDisplayMetrics());
    }

    private int sp2px(float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                sp, getResources().getDisplayMetrics());
    }

    public interface ItemClickListener {
        void ItemClick(int item);

        void MainClick();
    }

    private ItemClickListener listener;

    public void setItemClickListener(ItemClickListener listener) {
        this.listener = listener;
    }

}

完善中。。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值