自定义扇形菜单

 

自定义控件

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.BounceInterpolator;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;



public class PiemenuView extends View {
   private final String TAG = "PiemenuView";
   private Paint mPiemenuBgPaint;//背景画笔
   private int mPiemenuBgColor;//背景颜色
   private Paint mPiemenuThemePaint;//主题画笔
   private int mPiemenuThemeColor;//主题颜色
   private int mPiemenuInvalidThemeColor;//无效主题颜色
   private int mPiemenuThemeSelectColor;//选中颜色
   private int mPiemenuLineColor;//分割线颜色
   private int mMenuiconGauge;//icon边距
   private int mMenuBgRadiu = 100;//圆的半径
   private int mMenuBgFixedRadiu = 100;//圆的最小半径
   private boolean mIsOpenMenu = false;
   private boolean mIsOpenNing = false;//是不是打开中
   private long mAnimatorDuration = 1000;//动画时间
   private float mmMenuBgMaxRadiu = 0;
   private int mMsgNum = 0;

   private int mDefultViewWhith = 500;//自适应时view的宽高
   private int mWidth;
   private int mHeight;
   private Bitmap mMenuiconBitmap;
   private int mDownX;
   private int mDowny;

   private float mProgressOpen = 0;//打开进度
   private float mMaxProgressOpen = 1000f;//打开进度
   private float mMenuIconProgress = 100f;
   ValueAnimator mOpenAnimator = ValueAnimator.ofFloat(0f, mMaxProgressOpen);//打开动画 百分比
   ValueAnimator mCloseAnimator = ValueAnimator.ofFloat(mMaxProgressOpen, 0f);//打开动画 百分比
   ValueAnimator mMenuiconElasticityAnimator = ValueAnimator.ofFloat(30f, 0f);//打开动画 百分比
   private float mCenterx;
   private float mCentery;
   private int mBitmapWidth;//图片宽度
   private int mBitmapHeight;//图片高度

   private int mSmallFanNum = 15;//小扇形一圈数量
   private float mSmallFanAngle = 0;//小扇形角度
   private float mSmallFanRadio = 430.0f;//小扇形半径
   private float mStartAngle = 114;
   private float mSmallFanAngleRounded = 28.0f;//小扇形圆角直径
   private double mSmallFanCircleAngle = 0;//小扇形与圆心岔开角度

   private int mBigFanNum = 20;//大扇形一圈数量
   private float mBigFanAngle = 0;//大扇形角度
   private float mBigFanRadio = 650.0f;//大扇形半径
   private float mBigFanAngleRounded = 44.0f;//大扇形圆角直径
   private double mBigFanCircleAngle = 0;//大扇形与圆心岔开角度

   private int lineWith = 2;//分割线宽度
   private List<itemIconEntity> mItemIconList1 = new ArrayList<>();//第一排图标
   private List<itemIconEntity> mItemIconList2 = new ArrayList<>();//第二排图标

   private float mSmallFanDrawNum = 8;//小扇形个数
   private float mBigFanDrawNum = 10;//小扇形个数

   private int IconMagin = 150;//icon 距离弧线的距离

   private float[] mSmallFanOpenProgress;
   private float[] mBigFanOpenProgress;
   private float mMenuiconElasticity = 0;//icon点击弹性

   private float mSwichButtonRadio = 16;//切换按钮圆角
   private float mSwichButtonH = 350;//高度
   private float mSwichButtonW = mSwichButtonH * 64 / 135;//宽度

   public static final int PIEMENU_ITEM_TYPE_SMALL = 0;//小圆类型
   public static final int PIEMENU_ITEM_TYPE_BIG = 1;//大圆类型


   private onPiemenuItemClickListener monPiemenuItemClickListener;
   private boolean mIsChekeOne = true;
   private Bitmap SwithOneBitmap;//切换1选中图片
   private Bitmap SwithOneNoBitmap;
   private Bitmap SwithTwoBitmap;
   private Bitmap SwithTwoNoBitmap;
   private boolean mIsHaveInvalid = true;//拥有无效的功能
   public static final String IS_HAVE_INVALID_KEY = "PiemenuView_IS_HAVE_INVALID_KEY";
   private Bitmap MsgSwithTwoNoBitmap;//消息下边图片


   public void setmMsgNum(int mMsgNum) {
      this.mMsgNum = mMsgNum;
      invalidate();
   }

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

   public PiemenuView(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
   }

   public PiemenuView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init(context, attrs);
   }

   public void setmIsHaveInvalid(boolean mIsHaveInvalid) {
      this.mIsHaveInvalid = mIsHaveInvalid;
      invalidate();
   }

   private void init(Context context, AttributeSet attrs) {
      TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PiemenuView);
      mPiemenuBgColor = typedArray.getColor(R.styleable.PiemenuView_piemenu_bg_color, Color.parseColor("#80000000"));
      mPiemenuThemeColor = typedArray.getColor(R.styleable.PiemenuView_piemenu_theme_color, Color.parseColor("#2AB7D1"));
      mPiemenuInvalidThemeColor = typedArray.getColor(R.styleable.PiemenuView_piemenu_theme_invalid_color, Color.parseColor("#68DAEF"));
      mPiemenuThemeSelectColor = typedArray.getColor(R.styleable.PiemenuView_piemenu_theme_Select_color, Color.parseColor("#097185"));
      mPiemenuLineColor = typedArray.getColor(R.styleable.PiemenuView_piemenu_line_color, Color.parseColor("#9DDAE6"));
      mDefultViewWhith = typedArray.getDimensionPixelSize(R.styleable.PiemenuView_piemenu_defult_whith, 500);
      mMenuiconGauge = typedArray.getDimensionPixelSize(R.styleable.PiemenuView_piemenu_menuicon_gauge, 10);
      mMenuBgRadiu = typedArray.getDimensionPixelSize(R.styleable.PiemenuView_piemenu_menu_bg_radiu, 0);
      mSmallFanRadio = typedArray.getDimensionPixelSize(R.styleable.PiemenuView_piemenu_small_fan_radio, 430);
      mBigFanRadio = typedArray.getDimensionPixelSize(R.styleable.PiemenuView_piemenu_big_fan_radio, 650);
      mAnimatorDuration = typedArray.getInteger(R.styleable.PiemenuView_piemenu_animator_duration, 500);
      mStartAngle = typedArray.getInteger(R.styleable.PiemenuView_piemenu_start_angle, 114);
      mSwichButtonH = typedArray.getDimensionPixelSize(R.styleable.PiemenuView_piemenu_swich_button_hight, 350);
      mMenuBgFixedRadiu = mMenuBgRadiu;
      mMenuiconBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_menu_icon);
      SwithOneBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_swith_one_icon);
      SwithOneNoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_swith_one_nocheke_icon);
      SwithTwoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_swith_two_icon);
      SwithTwoNoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_swith_two_nocheke_icon);
      MsgSwithTwoNoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_msg_icon);
      mSwichButtonW = mSwichButtonH * 64 / 135;
      mmMenuBgMaxRadiu = mMenuiconBitmap.getWidth() / 2 + 90;
      typedArray.recycle();
      mPiemenuBgPaint = new Paint();
      mPiemenuBgPaint.setColor(mPiemenuBgColor);  //设置画笔颜色
      mPiemenuBgPaint.setStyle(Paint.Style.FILL);//设置填充样式
      mPiemenuBgPaint.setStrokeWidth(1);//设置画笔宽度
      mPiemenuThemePaint = new Paint();
      mPiemenuThemePaint.setColor(mPiemenuThemeColor);  //设置画笔颜色
      mPiemenuThemePaint.setStyle(Paint.Style.FILL);//设置填充样式
      mPiemenuThemePaint.setStrokeWidth(3);//设置画笔宽度
      mPiemenuThemePaint.setTextSize(44);
      initAnimator();
      mSmallFanAngle = 360 / mSmallFanNum;
      mBigFanAngle = 360 / mBigFanNum;
      mSmallFanCircleAngle = getFanCircleRounded(mSmallFanRadio, mSmallFanAngleRounded / 2.0f);
      mBigFanCircleAngle = getFanCircleRounded(mBigFanRadio, mBigFanAngleRounded / 2.0f);
      mSmallFanOpenProgress = new float[(int) mSmallFanDrawNum];
      mBigFanOpenProgress = new float[(int) mBigFanDrawNum];
   }

   //获取扇形顶部小圆心到边的角度
   private double getFanCircleRounded(float fanRadiu, float smallCircleRadiu) {
//    fanRadiu  a
      double rounded = 0.0;
      double topLine = 2.0 * smallCircleRadiu;//b
      double rigntLine = fanRadiu - smallCircleRadiu;//c

      // 计算弧度表示的角
      double B = Math.acos((fanRadiu * fanRadiu + rigntLine * rigntLine - topLine * topLine) / (2.0 * fanRadiu * rigntLine));
      // 用角度表示的角
      rounded = Math.toDegrees(B);
      return rounded - 2.0;
   }

   //获取一个角度到圆心固定距离的x y 点
   private double[] getCoordByCenterDistance(float radian, float currentAdius) {

      return getCoordByCenterDistance(radian, currentAdius, mCenterx, mCentery);
   }

   private double[] getCoordByCenterDistance(float radian, float currentAdius, float mCenterx, float mCentery) {
      double radian2 = Math.toRadians(radian);

      //currentAdius 半径
      double[] mNewIndex = new double[2];
      mNewIndex[0] = mCenterx + Math.cos(radian2) * currentAdius;
      mNewIndex[1] = mCentery + Math.sin(radian2) * currentAdius;
      return mNewIndex;
   }

   private void initAnimator() {
      mMenuiconElasticityAnimator.setDuration(1000);
      mMenuiconElasticityAnimator.setRepeatCount(0);
      mMenuiconElasticityAnimator.setInterpolator(new BounceInterpolator());

      mOpenAnimator.setDuration(mAnimatorDuration);
      mOpenAnimator.setRepeatCount(0);
      mCloseAnimator.setDuration(mAnimatorDuration / 2);
      mCloseAnimator.setRepeatCount(0);
      mCloseAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
         @Override
         public void onAnimationUpdate(ValueAnimator valueAnimator) {
            mProgressOpen = (float) (valueAnimator.getAnimatedValue());
            if (mProgressOpen == 0f) {
               mIsOpenNing = false;
            }
            Log.d(TAG, "mProgressOpen==" + mProgressOpen);
            invalidate();
         }
      });
      mOpenAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
         @Override
         public void onAnimationUpdate(ValueAnimator valueAnimator) {
            mProgressOpen = (float) (valueAnimator.getAnimatedValue());
            if (mProgressOpen == mMaxProgressOpen) {
               mIsOpenNing = false;
            }
            Log.d(TAG, "mProgressOpen==" + mProgressOpen);
            invalidate();
         }
      });
      mMenuiconElasticityAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
         @Override
         public void onAnimationUpdate(ValueAnimator valueAnimator) {
            mMenuiconElasticity = (float) (valueAnimator.getAnimatedValue());
            invalidate();

         }
      });
   }

   @Override
   protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      //绘制背景
      if (mIsOpenMenu || mIsOpenNing) {
         mPiemenuBgPaint.setColor(Color.parseColor("#80000000"));
      } else {
         mPiemenuBgPaint.setColor(Color.TRANSPARENT);

      }
      canvas.drawRect(0, 0, mWidth, mHeight, mPiemenuBgPaint);
      //绘制图标和图标背景
      for (int i = 0; i < mBigFanDrawNum; i++) {
         drawMenuBigFan(canvas, i);
      }
      for (int i = 0; i < mSmallFanDrawNum; i++) {
         drawMenuSmallFan(canvas, i);
      }
      drawSwichButton(canvas);
      drawMenuIcon(canvas);
   }

   //绘制选择按钮
   private void drawSwichButton(Canvas canvas) {
//    mIsChekeOne
      float mAlpha = 255 * mProgressOpen / mMaxProgressOpen;
      mPiemenuThemePaint.setAlpha((int) mAlpha);
      float SwichProgress = mSwichButtonW - mSwichButtonW * mProgressOpen / mMaxProgressOpen;
      float left = 0 - mSwichButtonRadio - SwichProgress;
      float top = mHeight / 2 - mSwichButtonH / 2;
      float right = mSwichButtonW - SwichProgress;
      float bootom = mHeight / 2 + mSwichButtonH / 2;
      RectF rectF = new RectF(left, top, right, bootom);
      canvas.drawRoundRect(rectF, mSwichButtonRadio, mSwichButtonRadio, mPiemenuThemePaint);
      Bitmap itemIcon;
      if (mIsChekeOne) {
         itemIcon = SwithOneBitmap;
      } else {
         itemIcon = SwithOneNoBitmap;
      }
      RectF rectFOne = new RectF(mSwichButtonW / 2 - itemIcon.getWidth() / 2 - SwichProgress, top + 26, mSwichButtonW / 2 + itemIcon.getWidth() / 2 - SwichProgress,
            top + 26 + itemIcon.getHeight());

      canvas.drawBitmap(itemIcon, null, rectFOne, mPiemenuThemePaint);

      Bitmap itemIconTwo;
      if (mIsChekeOne) {
         itemIconTwo = SwithTwoNoBitmap;
      } else {
         itemIconTwo = SwithTwoBitmap;
      }

      RectF rectFTwo = new RectF(mSwichButtonW / 2 - itemIconTwo.getWidth() / 2 - SwichProgress, bootom - 26 - itemIconTwo.getHeight(),
            mSwichButtonW / 2 + itemIconTwo.getWidth() / 2 - SwichProgress,
            bootom - 26);
      canvas.drawBitmap(itemIconTwo, null, rectFTwo, mPiemenuThemePaint);
      mPiemenuThemePaint.setColor(Color.parseColor("#FFFFFF"));
      mPiemenuThemePaint.setAlpha((int) mAlpha);
      canvas.drawRect(36 - SwichProgress, (top + bootom) / 2 - 1, right - 36 - SwichProgress, (top + bootom) / 2 + 1, mPiemenuThemePaint);
      mPiemenuThemePaint.setColor(mPiemenuThemeColor);
      mPiemenuThemePaint.setAlpha(255);
   }

   //绘制大扇形
   private void drawMenuBigFan(Canvas canvas, int index) {
      int FristNum = 2;
      float afterFristNum = 5;
      float mIndexAngle = mStartAngle + mBigFanAngle * index;
      float mSmallPress = 0; //单个进度

      int mAnimationIndex = 0;
      if (index < FristNum) {
         mAnimationIndex = 0;
      } else {
         mAnimationIndex = (int) (index - FristNum);
      }

      if (!mIsOpenMenu) {
         mAnimationIndex = mBigFanOpenProgress.length - 1 - mAnimationIndex;
      }
      float SmallitemProgress = ((mMaxProgressOpen - mMaxProgressOpen / mMenuIconProgress) / 4) / (mBigFanDrawNum - FristNum);
      float itemProgress = (mMaxProgressOpen - mMaxProgressOpen / mMenuIconProgress - SmallitemProgress * afterFristNum) / mBigFanDrawNum;//单个进度
      if (mProgressOpen > mMaxProgressOpen / mMenuIconProgress + SmallitemProgress * afterFristNum + itemProgress * mAnimationIndex) {
         mSmallPress =
               (mProgressOpen - mMaxProgressOpen / mMenuIconProgress - SmallitemProgress * afterFristNum - itemProgress * mAnimationIndex) * mMaxProgressOpen / itemProgress;
      } else {
         return;
      }
      if (index < 2 && mSmallPress < mMaxProgressOpen / 1.5) {
         return;
      }
      if (mSmallPress > mMaxProgressOpen) {
         mSmallPress = mMaxProgressOpen;
      }
      mBigFanOpenProgress[index] = mSmallPress;
//    if (!mIsOpenMenu) {
//       index = (mBigFanOpenProgress.length - 1) - index - FristNum;
//       if (index < FristNum) {
//          index = mBigFanOpenProgress.length - 1;
//       }
//
//    }


      double[] center = getCoordByCenterDistance(180 + mIndexAngle + mBigFanAngle / 2f,
            mBigFanRadio * (mMaxProgressOpen - mBigFanOpenProgress[index]) / mMaxProgressOpen);


//    //画扇形
      float radio = mBigFanRadio - mBigFanAngleRounded / 2f;

      mPiemenuThemePaint.setColor(mPiemenuLineColor);
      mPiemenuThemePaint.setStyle(Paint.Style.FILL);
      //画扇形
      RectF mSmallRectfLine2 = new RectF((float) (center[0] - radio), (float) (center[1] - radio), (float) (center[0] + radio), (float) (center[1] + radio));

      canvas.drawArc(mSmallRectfLine2, mIndexAngle, mBigFanAngle, true, mPiemenuThemePaint);
      //绘制圆圈
      double[] smacIndexLine = getCoordByCenterDistance((float) (mBigFanCircleAngle + mIndexAngle), mBigFanRadio - mBigFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      double[] smacIndexLine2 = getCoordByCenterDistance((float) (mIndexAngle + mBigFanAngle - mBigFanCircleAngle),
            mBigFanRadio - mBigFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      canvas.drawCircle((float) smacIndexLine[0], (float) smacIndexLine[1], mBigFanAngleRounded / 2f, mPiemenuThemePaint);
      canvas.drawCircle((float) smacIndexLine2[0], (float) smacIndexLine2[1], mBigFanAngleRounded / 2f, mPiemenuThemePaint);

      RectF mSmallRectfLine = new RectF((float) (center[0] - mBigFanRadio), (float) (center[1] - mBigFanRadio), (float) (center[0] + mBigFanRadio), (float) (center[1] + mBigFanRadio));
      canvas.drawArc(mSmallRectfLine, (float) (mIndexAngle + mBigFanCircleAngle), (float) (mBigFanAngle - 2.0 * mBigFanCircleAngle), true,
            mPiemenuThemePaint);
      mPiemenuThemePaint.setColor(mPiemenuThemeColor);
      mPiemenuThemePaint.setStyle(Paint.Style.FILL);

      int positon = index - 3;
      if (index > 2 && positon < mItemIconList2.size()) {
         itemIconEntity itemData = mItemIconList2.get(positon);
         if (itemData.ismIsSelect()) {
            mPiemenuThemePaint.setColor(mPiemenuThemeSelectColor);
         }
      }
      RectF mSmallRectf2 = new RectF((float) (center[0] - radio), (float) (center[1] - radio), (float) (center[0] + radio), (float) (center[1] + radio));
      canvas.drawArc(mSmallRectf2, mIndexAngle + 0.2f, mBigFanAngle - 0.4f, true, mPiemenuThemePaint);


//    //绘制圆圈
      double[] smacIndex = getCoordByCenterDistance((float) (mBigFanCircleAngle + mIndexAngle), mBigFanRadio - mBigFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      double[] smacIndex2 = getCoordByCenterDistance((float) (mIndexAngle + mBigFanAngle - mBigFanCircleAngle),
            mBigFanRadio - mBigFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      canvas.drawCircle((float) smacIndex[0], (float) smacIndex[1], mBigFanAngleRounded / 2f - lineWith, mPiemenuThemePaint);
      canvas.drawCircle((float) smacIndex2[0], (float) smacIndex2[1], mBigFanAngleRounded / 2f - lineWith, mPiemenuThemePaint);
//
      RectF mSmallRectf = new RectF((float) (center[0] - mBigFanRadio + lineWith), (float) (center[1] - mBigFanRadio + lineWith), (float) (center[0] + mBigFanRadio - lineWith),
            (float) (center[1] + mBigFanRadio - lineWith));
      canvas.drawArc(mSmallRectf, (float) (mIndexAngle + mBigFanCircleAngle), (float) (mBigFanAngle - 2.0 * mBigFanCircleAngle), true,
            mPiemenuThemePaint);
      mPiemenuThemePaint.setColor(mPiemenuThemeColor);

      //绘制icon
      if (index > 2 && positon < mItemIconList2.size()) {
         itemIconEntity itemData = mItemIconList2.get(positon);
         Bitmap itemIcon = BitmapFactory.decodeResource(getResources(), itemData.mItemIcon);
         double[] centerBitmap = getCoordByCenterDistance(mIndexAngle + mBigFanAngle / 2, mBigFanRadio - IconMagin, (float) center[0], (float) center[1]);


         int bitmapLeft = (int) (centerBitmap[0] - itemIcon.getWidth() / 2f);
         int bitmapTop = (int) (centerBitmap[1] - itemIcon.getHeight() / 2f);
         int bitmapRight = (int) (centerBitmap[0] + itemIcon.getWidth() / 2f);
         int bitmapBootom = (int) (centerBitmap[1] + itemIcon.getHeight() / 2f);
         Rect bitmapRect = new Rect(bitmapLeft, bitmapTop,
               bitmapRight, bitmapBootom);
         canvas.drawBitmap(itemIcon, null, bitmapRect, mPiemenuThemePaint);

         //绘制有消息图标
         if (itemData.mIsHaveMassg) {
            Bitmap itemMsgIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_have_messager_icon);
            Rect bitmapMsgRect = new Rect((int) (bitmapRight - itemMsgIcon.getWidth() / 2f), (int) (bitmapTop - itemMsgIcon.getHeight() / 2f),
                  (int) (bitmapRight + itemMsgIcon.getWidth() / 2f),
                  (int) (bitmapTop + itemMsgIcon.getHeight() / 2f));
            canvas.drawBitmap(itemMsgIcon, null, bitmapMsgRect, mPiemenuThemePaint);
         }
         //绘制消息
         if (itemData.mShowNum > 0) {
            String mNum = itemData.mShowNum + "";
            Rect rect = new Rect();
            mPiemenuThemePaint.getTextBounds(mNum, 0, mNum.length(), rect);
            int textWith = rect.width();
            int textheight = rect.height();
            mPiemenuThemePaint.setColor(Color.parseColor("#FFFFFF"));
            canvas.drawCircle(bitmapRight, bitmapTop, textWith / 2f + 20, mPiemenuThemePaint);
            mPiemenuThemePaint.setColor(mPiemenuThemeColor);
            canvas.drawText(mNum, bitmapRight - textWith / 2 - 5, bitmapTop + textheight / 2, mPiemenuThemePaint);
         }

      }


   }

   //绘制小扇形
   private void drawMenuSmallFan(Canvas canvas, float index) {
      int FristNum = 2;

      float mIndexAngle = mStartAngle + mSmallFanAngle * index;
      float mSmallPress = 0; //单个进度
      float itemProgress = ((mMaxProgressOpen - mMaxProgressOpen / mMenuIconProgress) / 4) / (mSmallFanDrawNum - FristNum);//单个进度
      int mAnimationIndex = 0;
      if (index < FristNum) {
         mAnimationIndex = 0;
      } else {
         mAnimationIndex = (int) (index - FristNum);
      }
      if (!mIsOpenMenu) {
         mAnimationIndex = mSmallFanOpenProgress.length - 1 - mAnimationIndex;
      }

      if (mProgressOpen > mMaxProgressOpen / mMenuIconProgress + itemProgress * mAnimationIndex) {
         mSmallPress = (mProgressOpen - mMaxProgressOpen / mMenuIconProgress - itemProgress * mAnimationIndex) * mMaxProgressOpen / itemProgress;
      } else {
         return;
      }
      if (mSmallPress < mMaxProgressOpen / 2) {
         return;
      }
      if (mSmallPress > mMaxProgressOpen) {
         mSmallPress = mMaxProgressOpen;
      }
      mSmallFanOpenProgress[(int) index] = mSmallPress;
      double[] center = getCoordByCenterDistance(180 + mIndexAngle + mSmallFanAngle / 2f,
            mSmallFanRadio * (mMaxProgressOpen - mSmallFanOpenProgress[(int) index]) / mMaxProgressOpen);


//    //画扇形
      float radio = mSmallFanRadio - mSmallFanAngleRounded / 2f;
      mPiemenuThemePaint.setColor(mPiemenuLineColor);
      mPiemenuThemePaint.setStyle(Paint.Style.FILL);
      //画扇形
      RectF mSmallRectfLine2 = new RectF((float) (center[0] - radio), (float) (center[1] - radio), (float) (center[0] + radio), (float) (center[1] + radio));

      canvas.drawArc(mSmallRectfLine2, mIndexAngle, mSmallFanAngle, true, mPiemenuThemePaint);
      //绘制圆圈
      double[] smacIndexLine = getCoordByCenterDistance((float) (mSmallFanCircleAngle + mIndexAngle), mSmallFanRadio - mSmallFanAngleRounded / 2f
            , (float) center[0], (float) center[1]);
      double[] smacIndexLine2 = getCoordByCenterDistance((float) (mIndexAngle + mSmallFanAngle - mSmallFanCircleAngle),
            mSmallFanRadio - mSmallFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      canvas.drawCircle((float) smacIndexLine[0], (float) smacIndexLine[1], mSmallFanAngleRounded / 2f, mPiemenuThemePaint);
      canvas.drawCircle((float) smacIndexLine2[0], (float) smacIndexLine2[1], mSmallFanAngleRounded / 2f, mPiemenuThemePaint);

      RectF mSmallRectfLine = new RectF((float) (center[0] - mSmallFanRadio), (float) (center[1] - mSmallFanRadio), (float) (center[0] + mSmallFanRadio),
            (float) (center[1] + mSmallFanRadio));
      canvas.drawArc(mSmallRectfLine, (float) (mIndexAngle + mSmallFanCircleAngle), (float) (mSmallFanAngle - 2.0 * mSmallFanCircleAngle), true, mPiemenuThemePaint);
      if (mIsHaveInvalid) {
         mPiemenuThemePaint.setColor(mPiemenuInvalidThemeColor);
      } else {
         mPiemenuThemePaint.setColor(mPiemenuThemeColor);
      }
      mPiemenuThemePaint.setStyle(Paint.Style.FILL);
      int positon = (int) (index - 2);
      if (index > 1 && positon < mItemIconList1.size()) {
         itemIconEntity itemData = mItemIconList1.get(positon);
         if (itemData.ismIsSelect()) {
            mPiemenuThemePaint.setColor(mPiemenuThemeSelectColor);
         }
      } else {
         if (positon < 0 || positon > mItemIconList1.size()) {
            mPiemenuThemePaint.setColor(mPiemenuThemeColor);
         }
      }


      RectF mSmallRectf2 = new RectF((float) (center[0] - radio), (float) (center[1] - radio), (float) (center[0] + radio), (float) (center[1] + radio));
      canvas.drawArc(mSmallRectf2, mIndexAngle + 0.2f, mSmallFanAngle - 0.4f, true, mPiemenuThemePaint);

//    //绘制圆圈
      double[] smacIndex = getCoordByCenterDistance((float) (mSmallFanCircleAngle + mIndexAngle), mSmallFanRadio - mSmallFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      double[] smacIndex2 = getCoordByCenterDistance((float) (mIndexAngle + mSmallFanAngle - mSmallFanCircleAngle),
            mSmallFanRadio - mSmallFanAngleRounded / 2f, (float) center[0], (float) center[1]);
      canvas.drawCircle((float) smacIndex[0], (float) smacIndex[1], mSmallFanAngleRounded / 2f - lineWith, mPiemenuThemePaint);
      canvas.drawCircle((float) smacIndex2[0], (float) smacIndex2[1], mSmallFanAngleRounded / 2f - lineWith, mPiemenuThemePaint);
//
      RectF mSmallRectf = new RectF((float) (center[0] - mSmallFanRadio + lineWith), (float) (center[1] - mSmallFanRadio + lineWith), (float) (center[0] + mSmallFanRadio - lineWith),
            (float) (center[1] + mSmallFanRadio - lineWith));
      canvas.drawArc(mSmallRectf, (float) (mIndexAngle + mSmallFanCircleAngle), (float) (mSmallFanAngle - 2.0 * mSmallFanCircleAngle), true, mPiemenuThemePaint);
      mPiemenuThemePaint.setColor(mPiemenuThemeColor);

      //绘制icon

      if (index > 1 && positon < mItemIconList1.size()) {
         itemIconEntity itemData = mItemIconList1.get(positon);
         Bitmap itemIcon = BitmapFactory.decodeResource(getResources(), itemData.mItemIcon);

         double[] centerBitmap = getCoordByCenterDistance(mIndexAngle + mSmallFanAngle / 2, mSmallFanRadio - IconMagin, (float) center[0], (float) center[1]);
         int bitmapLeft = (int) (centerBitmap[0] - itemIcon.getWidth() / 2f);
         int bitmapTop = (int) (centerBitmap[1] - itemIcon.getHeight() / 2f);
         int bitmapRight = (int) (centerBitmap[0] + itemIcon.getWidth() / 2f);
         int bitmapBootom = (int) (centerBitmap[1] + itemIcon.getHeight() / 2f);
         Rect bitmapRect = new Rect(bitmapLeft, bitmapTop,
               bitmapRight, bitmapBootom);
         if (mIsHaveInvalid && positon != 0) {
            mPiemenuThemePaint.setAlpha((int) (255f * 0.3f));
         }
         canvas.drawBitmap(itemIcon, null, bitmapRect, mPiemenuThemePaint);
         mPiemenuThemePaint.setAlpha(255);
         //绘制有消息图标
         if (itemData.mIsHaveMassg) {
            Bitmap itemMsgIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.piemenu_have_messager_icon);
            Rect bitmapMsgRect = new Rect((int) (bitmapRight - itemMsgIcon.getWidth() / 2f), (int) (bitmapTop - itemMsgIcon.getHeight() / 2f),
                  (int) (bitmapRight + itemMsgIcon.getWidth() / 2f),
                  (int) (bitmapTop + itemMsgIcon.getHeight() / 2f));
            canvas.drawBitmap(itemMsgIcon, null, bitmapMsgRect, mPiemenuThemePaint);
         }
         //绘制消息
         if (itemData.mShowNum > 0) {
            String mNum = itemData.mShowNum + "";
            Rect rect = new Rect();
            mPiemenuThemePaint.getTextBounds(mNum, 0, mNum.length(), rect);
            int textWith = rect.width();
            int textheight = rect.height();
            mPiemenuThemePaint.setColor(Color.parseColor("#FFFFFF"));
            canvas.drawCircle(bitmapRight, bitmapTop, textWith / 2f + 15, mPiemenuThemePaint);
            mPiemenuThemePaint.setColor(mPiemenuThemeColor);
            canvas.drawText(mNum, bitmapRight - textWith / 2 - 5, bitmapTop + textheight / 2, mPiemenuThemePaint);
         }
      }
   }


   private void drawMenuIcon(Canvas canvas) {
      //绘制图标

      //绘制底部圆圈

//    mmMenuBgMaxRadiu 最大半径
      float oPenRadio = mmMenuBgMaxRadiu - mMenuBgFixedRadiu;
      float addRadio = (mProgressOpen * mMenuIconProgress / mMaxProgressOpen) * oPenRadio;

      mMenuBgRadiu = (int) (mMenuBgFixedRadiu + addRadio);
      if (mMenuBgRadiu > mmMenuBgMaxRadiu) {
         mMenuBgRadiu = (int) mmMenuBgMaxRadiu;
      }
      canvas.drawCircle(mCenterx, mCentery, mMenuBgRadiu, mPiemenuThemePaint);


      if (mMenuBgRadiu == (int) mmMenuBgMaxRadiu) {
         RectF ArcRect = new RectF(mCenterx - mmMenuBgMaxRadiu - 0, mCentery - mmMenuBgMaxRadiu - 0, mCenterx + mmMenuBgMaxRadiu + 0,
               mCentery + mmMenuBgMaxRadiu + 0);
         mPiemenuThemePaint.setColor(mPiemenuLineColor);
         mPiemenuThemePaint.setStyle(Paint.Style.STROKE);
         canvas.drawArc(ArcRect, 0, 360, false, mPiemenuThemePaint);
         mPiemenuThemePaint.setColor(mPiemenuThemeColor);
         mPiemenuThemePaint.setStyle(Paint.Style.FILL);
      }
      canvas.drawBitmap(mMenuiconBitmap, null, new Rect((int) (mCenterx - mBitmapWidth / 2 - mMenuiconElasticity), (int) mCentery - mBitmapHeight / 2,
            (int) (mCenterx + mBitmapWidth / 2 + mMenuiconElasticity),
            (int) mCentery + mBitmapHeight / 2), mPiemenuThemePaint);

      if (mMsgNum>0) {
         //找到圆心
         int halfHeight = (MsgSwithTwoNoBitmap.getHeight() / 2);
         int halfWidth = (MsgSwithTwoNoBitmap.getWidth()/2);
         int msgIconCentery = (int) mCentery - mBitmapHeight / 2+halfHeight;
         int msgIconCenterx = (int) (mCenterx + mBitmapWidth / 2 + mMenuiconElasticity)-halfWidth;
         RectF rectMsgFOne = new RectF(msgIconCenterx- halfWidth, msgIconCentery-halfHeight,
               msgIconCenterx+ halfWidth,msgIconCentery+halfHeight);
         canvas.drawBitmap(MsgSwithTwoNoBitmap, null, rectMsgFOne, mPiemenuThemePaint);
         String mNum = mMsgNum+ "";
         Rect rect = new Rect();
         mPiemenuThemePaint.getTextBounds(mNum, 0, mNum.length(), rect);
         int textWith = rect.width();
         int textheight = rect.height();
         mPiemenuThemePaint.setColor(Color.parseColor("#FFFFFF"));
         canvas.drawText(mNum, msgIconCenterx - textWith / 2 , msgIconCentery + textheight / 2, mPiemenuThemePaint);
         mPiemenuThemePaint.setColor(mPiemenuThemeColor);
      }
   }

   @Override
   protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
      super.onLayout(changed, left, top, right, bottom);
      mWidth = getWidth();
      mHeight = getHeight();
      int rightBitmap = mWidth - mMenuiconGauge;
      int bootomBitmap = mHeight - mMenuiconGauge - 44;
      mBitmapWidth = mMenuiconBitmap.getWidth();
      mBitmapHeight = mMenuiconBitmap.getHeight();
      int leftBitmap = rightBitmap - mBitmapWidth;
      int topBitmap = bootomBitmap - mBitmapHeight;
      mCenterx = (rightBitmap + leftBitmap) / 2;
      mCentery = (topBitmap + bootomBitmap) / 2;
      mBigFanRadio = mWidth * 373f / 375f - (mWidth - mCenterx);
      mSmallFanRadio = mWidth * 264f / 375f - (mWidth - mCenterx);
      mmMenuBgMaxRadiu = mWidth * 136f / 375f - (mWidth - mCenterx);
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
      int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
      int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
      int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
      setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? measureWidth : mDefultViewWhith, (measureHeightMode == MeasureSpec.EXACTLY) ? measureHeight : mDefultViewWhith);
   }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
      super.onTouchEvent(event);
      int y = (int) event.getY();
      int x = (int) event.getX();
      switch (event.getAction()) {
         case MotionEvent.ACTION_DOWN:
            mDownX = x;
            mDowny = y;
            int right = mWidth - mMenuiconGauge;
            int bootom = mHeight - mMenuiconGauge - 44;
            int left = right - mMenuiconBitmap.getWidth();
            int top = bootom - mMenuiconBitmap.getHeight();
            if (mIsOpenMenu) {
               return true;
            } else if (mDownX > left && mDownX < right && mDowny > top && mDowny < bootom) {
               return true;
            }
            break;
         case MotionEvent.ACTION_MOVE:

            break;
         case MotionEvent.ACTION_UP:
            if (Math.abs(x - mDownX) > 100 || Math.abs(y - mDowny) > 100) {
               //点下滑动了
               if (isOpen()) {
                  return true;
               }
            }
            //正在执行动画不用管点击事件
            if (mIsOpenNing) {
               return true;
            }
            //看看是不是点的按钮
            if (ClickMenuIcon()) {
               return true;
            }
            if (ClickMenuItem()) {
               return true;
            }

            if (clickSwichButton()) {
               return true;
            }
            closeView(false);

            break;
      }
      return false;
   }

   //点击切换按钮
   private boolean clickSwichButton() {
//    mIsChekeOne
      float left = 0 - mSwichButtonRadio;
      float top = mHeight / 2 - mSwichButtonH / 2;
      float right = mSwichButtonW;
      float bootom = mHeight / 2 + mSwichButtonH / 2;

      Bitmap itemIcon;
      if (mIsChekeOne) {
         itemIcon = SwithOneBitmap;
      } else {
         itemIcon = SwithOneNoBitmap;
      }
      if (mDownX > (mSwichButtonW / 2 - itemIcon.getWidth() / 2) && mDownX < (mSwichButtonW / 2 + itemIcon.getWidth() / 2) && mDowny > (top + 26) && mDowny < top + 26 + itemIcon.getHeight()) {
         //点击1
         mIsChekeOne = true;
         invalidate();
         if (monPiemenuItemClickListener != null) {
            monPiemenuItemClickListener.onSwichButtonClick(mIsChekeOne);
         }
         return true;
      }
      Bitmap itemIconTwo;
      if (mIsChekeOne) {
         itemIconTwo = SwithTwoNoBitmap;
      } else {
         itemIconTwo = SwithTwoBitmap;
      }
      if (mDownX > (mSwichButtonW / 2 - itemIconTwo.getWidth() / 2) && mDownX < (mSwichButtonW / 2 + itemIconTwo.getWidth() / 2) && mDowny > (bootom - 26 - itemIconTwo.getHeight()) && mDowny < (bootom - 26)) {
         //点击2
         mIsChekeOne = false;
         invalidate();
         if (monPiemenuItemClickListener != null) {
            monPiemenuItemClickListener.onSwichButtonClick(mIsChekeOne);
         }
         return true;
      }
      if (mDownX > left && mDownX < right && mDowny > top && mDowny < bootom) {
         return true;
      }
      return false;

   }

   //看下是否点击的item
   private boolean ClickMenuItem() {
      double[] Index = getAngleDistanceByPoint(mDownX, mDowny);
      double radiusLength = Index[1];
      if (radiusLength > mBigFanRadio) {
         return false;
      }
      if (radiusLength > mSmallFanRadio) {
         double Bigposition = (Index[0] - mStartAngle) / mBigFanAngle;
         //点击的大圆
         int index = ((int) Bigposition) - 3;
         if (index >= 0 && index < mItemIconList2.size()) {
            for (itemIconEntity itemIconEntity : mItemIconList2) {
               itemIconEntity.setmIsSelect(false);
            }
            closeView(false);
            new Timer().schedule(new TimerTask() {
               @Override
               public void run() {
                  if (monPiemenuItemClickListener != null) {
                     monPiemenuItemClickListener.onPiemenuItem(PIEMENU_ITEM_TYPE_BIG, index);
                  }
               }
            }, mAnimatorDuration / 3); // 延时1秒

            invalidate();
            return true;
         }
         return false;
      }
      if (radiusLength > mmMenuBgMaxRadiu) {
         double Smallposition = (Index[0] - mStartAngle) / mSmallFanAngle;
         //点击的小圆
         int index = ((int) Smallposition) - 2;
         if (mIsHaveInvalid && index != 0) {
            return true;
         }
         if (index >= 0 && index < mItemIconList1.size()) {
            for (int i = 0; i < mItemIconList1.size(); i++) {
               if (i == index) {
                  mItemIconList1.get(i).setmIsSelect(true);
               } else {
                  mItemIconList1.get(i).setmIsSelect(false);
               }
            }
            closeView(false);
            if (monPiemenuItemClickListener != null) {
               monPiemenuItemClickListener.onPiemenuItem(PIEMENU_ITEM_TYPE_SMALL, index);
            }
            invalidate();
            return true;
         }
         return false;
      }
      return false;
   }


   public void setMonPiemenuItemClickListener(onPiemenuItemClickListener monPiemenuItemClickListener) {
      this.monPiemenuItemClickListener = monPiemenuItemClickListener;
   }

   //根据点获取和圆心的距离和角度
   private double[] getAngleDistanceByPoint(float Touchx, float Touchy) {
      float fLen = (float) Math.sqrt(Math.pow(mCenterx - Touchx, 2)
            + Math.pow(mCentery - Touchy, 2));


      //currentAdius 半径
      double radian = Math.acos((mCenterx - Touchx) / fLen);
      double[] mNewIndex = new double[2];
      double angle = 180 / (Math.PI / radian);

      if (mCentery - Touchy < 0) {
         angle = -angle;
      } else if ((mCentery - Touchy == 0) && (mCenterx - Touchx < 0)) {
         angle = 180;
      }

      mNewIndex[0] = angle + 180;
      ;
      mNewIndex[1] = fLen;
      return mNewIndex;
   }

   private boolean ClickMenuIcon() {
      int right = mWidth - mMenuiconGauge;
      int bootom = mHeight - mMenuiconGauge - 44;
      int left = right - mMenuiconBitmap.getWidth();
      int top = bootom - mMenuiconBitmap.getHeight();
      if (mDownX > left && mDownX < right && mDowny > top && mDowny < bootom) {
         //是按钮
         if (mIsOpenMenu) {
            //是打开 需要关闭
            closeView(true);
         } else {
            //是关闭需要打开
            openView();
         }
         return true;
      }
      return false;
   }

   @Override
   public boolean onKeyDown(int keyCode, KeyEvent event) {
      if (keyCode == KeyEvent.KEYCODE_BACK) {
         if (mIsOpenMenu || mIsOpenNing) {
            closeView(false);
            return true;
         }
         return super.onKeyDown(keyCode, event);
      }
      return super.onKeyDown(keyCode, event);
   }

   //关闭
   public void closeView(Boolean isIconAnimator) {
      if (!mIsOpenMenu) {
         return;
      }
      if (mIsOpenNing) {
         return;
      }
      mIsOpenMenu = false;
      mIsOpenNing = true;
      mCloseAnimator.start();
      if (isIconAnimator) {
         mMenuiconElasticityAnimator.start();
      }
   }

   //打开
   private void openView() {
      if (mIsOpenMenu) {
         return;
      }
      if (mIsOpenNing) {
         return;
      }
      mIsOpenMenu = true;
      mIsOpenNing = true;
      mOpenAnimator.start();
      mMenuiconElasticityAnimator.start();
   }

   private boolean isOpen() {
      return mIsOpenNing || mIsOpenMenu;
   }


   public void setmItemIconList1(List<itemIconEntity> mItemIconList1) {
      if (mItemIconList1 == null) {
         mItemIconList1 = new ArrayList<>();
      }
      this.mItemIconList1 = mItemIconList1;
      invalidate();
   }

   public void setmItemIconList2(List<itemIconEntity> mItemIconList2) {
      if (mItemIconList2 == null) {
         mItemIconList2 = new ArrayList<>();
      }
      this.mItemIconList2 = mItemIconList2;
      invalidate();
   }

   public void setmIsChekeOne(boolean mIsChekeOne) {
      this.mIsChekeOne = mIsChekeOne;
      invalidate();
   }

   public static class itemIconEntity implements Serializable {
      private int mItemIcon;
      private int mItemId;
      private boolean mIsSelect;
      private int mShowNum;
      private boolean mIsHaveMassg;

      public int getmShowNum() {
         return mShowNum;
      }

      public void setmShowNum(int mShowNum) {
         this.mShowNum = mShowNum;
      }

      public boolean ismIsHaveMassg() {
         return mIsHaveMassg;
      }

      public void setmIsHaveMassg(boolean mIsHaveMassg) {
         this.mIsHaveMassg = mIsHaveMassg;
      }

      public int getmItemIcon() {
         return mItemIcon;
      }

      public void setmItemIcon(int mItemIcon) {
         this.mItemIcon = mItemIcon;
      }

      public int getmItemId() {
         return mItemId;
      }

      public void setmItemId(int mItemId) {
         this.mItemId = mItemId;
      }

      public boolean ismIsSelect() {
         return mIsSelect;
      }

      public void setmIsSelect(boolean mIsSelect) {
         this.mIsSelect = mIsSelect;
      }
   }

   public static interface onPiemenuItemClickListener {
      void onPiemenuItem(int type, int position);

      void onSwichButtonClick(boolean isChickone);
   }

   public void notifyDataSetChanged() {
      invalidate();
   }
}

资源

<declare-styleable name="PiemenuView">
    <attr name="piemenu_bg_color" format="color" />
    <attr name="piemenu_theme_color" format="color" />
    <attr name="piemenu_theme_invalid_color" format="color" />
    <attr name="piemenu_theme_Select_color" format="color" />
    <attr name="piemenu_line_color" format="color" />
    <attr name="piemenu_defult_whith" format="dimension" />
    <attr name="piemenu_menuicon_gauge" format="dimension" />
    <attr name="piemenu_menu_bg_radiu" format="dimension" />
    <attr name="piemenu_animator_duration" format="integer" />
    <attr name="piemenu_small_fan_radio" format="dimension" />
    <attr name="piemenu_big_fan_radio" format="dimension" />
    <attr name="piemenu_swich_button_hight" format="dimension" />
    <attr name="piemenu_start_angle" format="integer" />
</declare-styleable>

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值