自定义控件 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>