DotImageView.java

package com.yw.game.floatmenu;import android.animation.Animator;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Camera;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Rect;import android.support.annotation.Nullable;import android.text.TextUtils;import android.util.AttributeSet;import android.view.View;import android.view.animation.LinearInterpolator;/** * Created by wengyiming on 2017/7/21. *//** * 00%=FF(不透明)    5%=F2    10%=E5    15%=D8    20%=CC    25%=BF    30%=B2    35%=A5    40%=99    45%=8c    50%=7F * 55%=72    60%=66    65%=59    70%=4c    75%=3F    80%=33    85%=21    90%=19    95%=0c    100%=00(全透明) */public class DotImageView extends View {    private static final String TAG = DotImageView.class.getSimpleName();    public static final int NORMAL = 0;//不隐藏    public static final int HIDE_LEFT = 1;//左边隐藏    public static final int HIDE_RIGHT = 2;//右边隐藏    private Paint mPaint;//用于画anything    private Paint mPaintBg;//用于画anything    private String dotNum = null;//红点数字    private float mAlphValue;//透明度动画值    private float mRolateValue = 1f;//旋转动画值    private boolean inited = false;//标记透明动画是否执行过,防止因onreseme 切换导致重复执行    private Bitmap mBitmap;//logo    private final int mLogoBackgroundRadius = dip2px(25);//logo的灰色背景圆的半径    private final int mLogoWhiteRadius = dip2px(20);//logo的白色背景的圆的半径    private final int mRedPointRadiusWithNum = dip2px(6);//红点圆半径    private final int mRedPointRadius = dip2px(3);//红点圆半径    private final int mRedPointOffset = dip2px(10);//红点对logo的偏移量,比如左红点就是logo中心的 x - mRedPointOffset    private boolean isDraging = false;//是否 绘制旋转放大动画,只有 非停靠边缘才绘制    private float scaleOffset;//放大偏移值    private ValueAnimator mDragingValueAnimator;//放大、旋转 属性动画    private LinearInterpolator mLinearInterpolator = new LinearInterpolator();//通用用加速器    public boolean mDrawDarkBg = true;//是否绘制黑色背景,当菜单关闭时,才绘制灰色背景    private static final float hideOffset = 0.4f;//往左右隐藏多少宽度的偏移值, 隐藏宽度的0.4    private Camera mCamera;//camera用于执行3D动画    private boolean mDrawNum = false;//只绘制红点还是红点+白色数字    private int mStatus = NORMAL;//0 正常,1 左,2右,3 中间方法旋转    private int mLastStatus = mStatus;    private Matrix mMatrix;    private boolean mIsResetPosition;    private int mBgColor = 0x99000000;    public void setBgColor(int bgColor) {        mBgColor = bgColor;    }    public void setDrawNum(boolean drawNum) {        this.mDrawNum = drawNum;    }    public void setDrawDarkBg(boolean drawDarkBg) {        mDrawDarkBg = drawDarkBg;        invalidate();    }    public int getStatus() {        return mStatus;    }    public void setStatus(int status) {        this.mStatus = status;        isDraging = false;        if (this.mStatus != NORMAL) {            setDrawNum(mDrawNum);            this.mDrawDarkBg = true;        }        invalidate();    }    public void setBitmap(Bitmap bitmap) {        mBitmap = bitmap;    }    public DotImageView(Context context, Bitmap bitmap) {        super(context);        this.mBitmap = bitmap;        init();    }    public DotImageView(Context context) {        super(context);        init();    }    public DotImageView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init();    }    public DotImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setTextSize(sp2px(10));        mPaint.setStyle(Paint.Style.FILL);        mPaintBg = new Paint();        mPaintBg.setAntiAlias(true);        mPaintBg.setStyle(Paint.Style.FILL);        mPaintBg.setColor(mBgColor);//60% 黑色背景 (透明度 40%)        mCamera = new Camera();        mMatrix = new Matrix();    }    /**     * 这个方法是否有优化空间     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int wh = mLogoBackgroundRadius * 2;        setMeasuredDimension(wh, wh);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        float centryX = getWidth() / 2;        float centryY = getHeight() / 2;        canvas.save();//保存一份快照,方便后面恢复        mCamera.save();        if (mStatus == NORMAL) {            if (mLastStatus != NORMAL) {                canvas.restore();//恢复画布的原始快照                mCamera.restore();            }            if (isDraging) {                //如果当前是拖动状态则放大并旋转                canvas.scale((scaleOffset + 1f), (scaleOffset + 1f), getWidth() / 2, getHeight() / 2);                if (mIsResetPosition) {                    //手指拖动后离开屏幕复位时使用 x轴旋转 3d动画                    mCamera.save();                    mCamera.rotateX(720 * scaleOffset);//0-720度 最多转两圈                    mCamera.getMatrix(mMatrix);                    mMatrix.preTranslate(-getWidth() / 2, -getHeight() / 2);                    mMatrix.postTranslate(getWidth() / 2, getHeight() / 2);                    canvas.concat(mMatrix);                    mCamera.restore();                } else {                    //手指拖动且手指未离开屏幕则使用 绕图心2d旋转动画                    canvas.rotate(60 * mRolateValue, getWidth() / 2, getHeight() / 2);                }            }        } else if (mStatus == HIDE_LEFT) {            canvas.translate(-getWidth() * hideOffset, 0);            canvas.rotate(-45, getWidth() / 2, getHeight() / 2);        } else if (mStatus == HIDE_RIGHT) {            canvas.translate(getWidth() * hideOffset, 0);            canvas.rotate(45, getWidth() / 2, getHeight() / 2);        }        canvas.save();        if (!isDraging) {            if (mDrawDarkBg) {                mPaintBg.setColor(mBgColor);                canvas.drawCircle(centryX, centryY, mLogoBackgroundRadius, mPaintBg);                // 60% 白色 (透明度 40%)                mPaint.setColor(0x99ffffff);            } else {                //100% 白色背景 (透明度 0%)                mPaint.setColor(0xFFFFFFFF);            }            if (mAlphValue != 0) {                mPaint.setAlpha((int) (mAlphValue * 255));            }            canvas.drawCircle(centryX, centryY, mLogoWhiteRadius, mPaint);        }        canvas.restore();        //100% 白色背景 (透明度 0%)        mPaint.setColor(0xFFFFFFFF);        int left = (int) (centryX - mBitmap.getWidth() / 2);        int top = (int) (centryY - mBitmap.getHeight() / 2);        canvas.drawBitmap(mBitmap, left, top, mPaint);        if (!TextUtils.isEmpty(dotNum)) {            int readPointRadus = (mDrawNum ? mRedPointRadiusWithNum : mRedPointRadius);            mPaint.setColor(Color.RED);            if (mStatus == HIDE_LEFT) {                canvas.drawCircle(centryX + mRedPointOffset, centryY - mRedPointOffset, readPointRadus, mPaint);                if (mDrawNum) {                    mPaint.setColor(Color.WHITE);                    canvas.drawText(dotNum, centryX + mRedPointOffset - getTextWidth(dotNum, mPaint) / 2, centryY - mRedPointOffset + getTextHeight(dotNum, mPaint) / 2, mPaint);                }            } else if (mStatus == HIDE_RIGHT) {                canvas.drawCircle(centryX - mRedPointOffset, centryY - mRedPointOffset, readPointRadus, mPaint);                if (mDrawNum) {                    mPaint.setColor(Color.WHITE);                    canvas.drawText(dotNum, centryX - mRedPointOffset - getTextWidth(dotNum, mPaint) / 2, centryY - mRedPointOffset + getTextHeight(dotNum, mPaint) / 2, mPaint);                }            } else {                if (mLastStatus == HIDE_LEFT) {                    canvas.drawCircle(centryX + mRedPointOffset, centryY - mRedPointOffset, readPointRadus, mPaint);                    if (mDrawNum) {                        mPaint.setColor(Color.WHITE);                        canvas.drawText(dotNum, centryX + mRedPointOffset - getTextWidth(dotNum, mPaint) / 2, centryY - mRedPointOffset + getTextHeight(dotNum, mPaint) / 2, mPaint);                    }                } else if (mLastStatus == HIDE_RIGHT) {                    canvas.drawCircle(centryX - mRedPointOffset, centryY - mRedPointOffset, readPointRadus, mPaint);                    if (mDrawNum) {                        mPaint.setColor(Color.WHITE);                        canvas.drawText(dotNum, centryX - mRedPointOffset - getTextWidth(dotNum, mPaint) / 2, centryY - mRedPointOffset + getTextHeight(dotNum, mPaint) / 2, mPaint);                    }                }            }        }        mLastStatus = mStatus;    }    public void setDotNum(int num, Animator.AnimatorListener l) {        if (!inited) {            startAnim(num, l);        } else {            refreshDot(num);        }    }    private void refreshDot(int num) {        if (num > 0) {            String dotNumTmp = String.valueOf(num);            if (!TextUtils.equals(dotNum, dotNumTmp)) {                dotNum = dotNumTmp;                invalidate();            }        } else {            dotNum = null;        }    }    public void startAnim(final int num, Animator.AnimatorListener l) {        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.f, 0.6f, 1f, 0.6f);        valueAnimator.setInterpolator(mLinearInterpolator);        valueAnimator.setDuration(3000);        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                mAlphValue = (float) animation.getAnimatedValue();                invalidate();            }        });        valueAnimator.addListener(l);        valueAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {                inited = true;                refreshDot(num);                mAlphValue = 0;            }            @Override            public void onAnimationCancel(Animator animation) {                mAlphValue = 0;            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        valueAnimator.start();    }    public void setDraging(boolean draging, float offset, boolean isResetPosition) {        isDraging = draging;        this.mIsResetPosition = isResetPosition;        if (offset > 0 && offset != this.scaleOffset) {            this.scaleOffset = offset;        }        if (isDraging && mStatus == NORMAL) {            if (mDragingValueAnimator != null) {                if (mDragingValueAnimator.isRunning()) return;            }            mDragingValueAnimator = ValueAnimator.ofFloat(0, 6f, 12f, 0f);            mDragingValueAnimator.setInterpolator(mLinearInterpolator);            mDragingValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    mRolateValue = (float) animation.getAnimatedValue();                    invalidate();                }            });            mDragingValueAnimator.addListener(new Animator.AnimatorListener() {                @Override                public void onAnimationStart(Animator animation) {                }                @Override                public void onAnimationEnd(Animator animation) {                    isDraging = false;                    mIsResetPosition = false;                }                @Override                public void onAnimationCancel(Animator animation) {                }                @Override                public void onAnimationRepeat(Animator animation) {                }            });            mDragingValueAnimator.setDuration(1000);            mDragingValueAnimator.start();        }    }    private int dip2px(float dipValue) {        final float scale = getContext().getResources().getDisplayMetrics().density;        return (int) (dipValue * scale + 0.5f);    }    private int sp2px(float spValue) {        final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;        return (int) (spValue * fontScale + 0.5f);    }    private float getTextHeight(String text, Paint paint) {        Rect rect = new Rect();        paint.getTextBounds(text, 0, text.length(), rect);        return rect.height() / 1.1f;    }    private float getTextWidth(String text, Paint paint) {        return paint.measureText(text);    }}

FloatItem.java

package com.yw.game.floatmenu;import android.graphics.Bitmap;import android.graphics.Color;/** * Created by wengyiming on 2017/7/21. */public class FloatItem {    public String title;    public int titleColor = Color.BLACK;    public int bgColor = Color.WHITE;    public Bitmap icon;    public String dotNum = null;    public FloatItem(String title, int titleColor, int bgColor, Bitmap icon, String dotNum) {        this.title = title;        this.titleColor = titleColor;        this.bgColor = bgColor;        this.icon = icon;        this.dotNum = dotNum;    }    public String getDotNum() {        return dotNum;    }    public FloatItem(String title, int titleColor, int bgColor, Bitmap bitmap) {        this.title = title;        this.titleColor = titleColor;        this.bgColor = bgColor;        this.icon = bitmap;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public int getTitleColor() {        return titleColor;    }    public void setTitleColor(int titleColor) {        this.titleColor = titleColor;    }    public int getBgColor() {        return bgColor;    }    public void setBgColor(int bgColor) {        this.bgColor = bgColor;    }    public Bitmap getIcon() {        return icon;    }    public void setIcon(Bitmap icon) {        this.icon = icon;    }    @Override    public boolean equals(Object obj) {        if (obj == null) {            return false;        }        if (obj == this) return true;        if (obj instanceof FloatItem) {            FloatItem floatItem = (FloatItem) obj;            return floatItem.title.equals(this.title);        } else {            return false;        }    }    @Override    public int hashCode() {        return title.hashCode();    }    @Override    public String toString() {        return "FloatItem{" +                "title='" + title + '\'' +                ", titleColor=" + titleColor +                ", bgColor=" + bgColor +                ", icon=" + icon +                ", dotNum='" + dotNum + '\'' +                '}';    }}

FloatLogoMenu.java

package com.yw.game.floatmenu;import android.animation.Animator;import android.animation.ValueAnimator;import android.app.Activity;import android.content.Context;import android.content.SharedPreferences;import android.graphics.Bitmap;import android.graphics.Color;import android.graphics.PixelFormat;import android.graphics.drawable.Drawable;import android.os.Build;import android.os.Bundle;import android.os.CountDownTimer;import android.os.Handler;import android.os.Looper;import android.text.TextUtils;import android.util.Log;import android.util.TypedValue;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.ViewGroup;import android.view.WindowManager;import android.view.animation.Interpolator;import android.view.animation.LinearInterpolator;import android.widget.LinearLayout;import java.util.ArrayList;import java.util.List;/** * Created by wengyiming on 2017/7/20. */public class FloatLogoMenu {    /**     * 记录 logo 停放的位置,以备下次恢复     */    private static final String LOCATION_X = "hintLocation";    private static final String LOCATION_Y = "locationY";    /**     * 悬浮球 坐落 左 右 标记     */    public static final int LEFT = 0;    public static final int RIGHT = 1;    /**     * 记录系统状态栏的高度     */    private int mStatusBarHeight;    /**     * 记录当前手指位置在屏幕上的横坐标值     */    private float mXInScreen;    /**     * 记录当前手指位置在屏幕上的纵坐标值     */    private float mYInScreen;    /**     * 记录手指按下时在屏幕上的横坐标的值     */    private float mXDownInScreen;    /**     * 记录手指按下时在屏幕上的纵坐标的值     */    private float mYDownInScreen;    /**     * 记录手指按下时在小悬浮窗的View上的横坐标的值     */    private float mXInView;    /**     * 记录手指按下时在小悬浮窗的View上的纵坐标的值     */    private float mYinview;    /**     * 记录屏幕的宽度     */    private int mScreenWidth;    /**     * 来自 activity 的 wManager     */    private WindowManager wManager;    /**     * 为 wManager 设置 LayoutParams     */    private WindowManager.LayoutParams wmParams;    /**     * 带透明度动画、旋转、放大的悬浮球     */    private DotImageView mFloatLogo;    /**     * 用于 定时 隐藏 logo的定时器     */    private CountDownTimer mHideTimer;    /**     * float menu的高度     */    private Handler mHandler = new Handler(Looper.getMainLooper());    /**     * 悬浮窗左右移动到默认位置 动画的 加速器     */    private Interpolator mLinearInterpolator = new LinearInterpolator();    /**     * 用于记录上次菜单打开的时间,判断时间间隔     */    private static double DOUBLE_CLICK_TIME = 0L;    /**     * 标记是否拖动中     */    private boolean isDraging = false;    /**     * 用于恢复悬浮球的location的属性动画值     */    private int mResetLocationValue;    /**     * 手指离开屏幕后 用于恢复 悬浮球的 logo 的左右位置     */    private Runnable updatePositionRunnable = new Runnable() {        @Override        public void run() {            isDraging = true;            checkPosition();        }    };    /**     * 这个事件不做任何事情、直接return false则 onclick 事件生效     */    private OnTouchListener mDefaultOnTouchListerner = new OnTouchListener() {        @Override        public boolean onTouch(View v, MotionEvent event) {            isDraging = false;            return false;        }    };    /**     * 这个事件用于处理移动、自定义点击或者其它事情,return true可以保证onclick事件失效     */    private OnTouchListener touchListener = new OnTouchListener() {        @Override        public boolean onTouch(View v, MotionEvent event) {            switch (event.getAction()) {                case MotionEvent.ACTION_DOWN:                    floatEventDown(event);                    break;                case MotionEvent.ACTION_MOVE:                    floatEventMove(event);                    break;                case MotionEvent.ACTION_UP:                case MotionEvent.ACTION_CANCEL:                    floatEventUp();                    break;            }            return true;        }    };    /**     * 菜单背景颜色     */    private int mBackMenuColor = 0xffe4e3e1;    /**     * 是否绘制红点数字     */    private boolean mDrawRedPointNum;    /**     * 是否绘制圆形菜单项,false绘制方形     */    private boolean mCicleMenuBg;    /**     * R.drawable.yw_game_logo     *     * @param floatItems     */    private Bitmap mLogoRes;    /**     * 用于显示在 mActivity 上的 mActivity     */    private Context mActivity;    /**     * 菜单 点击、关闭 监听     */    private FloatMenuView.OnMenuClickListener mOnMenuClickListener;    /**     * 停靠默认位置     */    private int mDefaultLocation = RIGHT;    /**     * 悬浮窗 坐落 位置     */    private int mHintLocation = mDefaultLocation;    /**     * 用于记录菜单项内容     */    private List mFloatItems = new ArrayList<>();    private LinearLayout rootViewRight;    private LinearLayout rootView;    private ValueAnimator valueAnimator;    private boolean isExpaned = false;    private Drawable mBackground;    private FloatLogoMenu(Builder builder) {        mBackMenuColor = builder.mBackMenuColor;        mDrawRedPointNum = builder.mDrawRedPointNum;        mCicleMenuBg = builder.mCicleMenuBg;        mLogoRes = builder.mLogoRes;        mActivity = builder.mActivity;        mOnMenuClickListener = builder.mOnMenuClickListener;        mDefaultLocation = builder.mDefaultLocation;        mFloatItems = builder.mFloatItems;        mBackground = builder.mDrawable;//        if (mActivity == null || mActivity.isFinishing() || mActivity.getWindowManager() == null) {//            throw new IllegalArgumentException("Activity = null, or Activity is isFinishing ,or this Activity`s  token is bad");//        }        if (mLogoRes == null) {            throw new IllegalArgumentException("No logo found,you can setLogo/showWithLogo to set a FloatLogo ");        }        if (mFloatItems.isEmpty()) {            throw new IllegalArgumentException("At least one menu item!");        }        initFloatWindow();        initTimer();        initFloat();    }    public void setFloatItemList(List floatItems) {        this.mFloatItems = floatItems;        caculateDotNum();    }    /**     * 初始化悬浮球 window     */    private void initFloatWindow() {        wmParams = new WindowManager.LayoutParams();        if (mActivity instanceof Activity) {            Activity activity = (Activity) mActivity;            wManager = activity.getWindowManager();            //类似dialog,寄托在activity的windows上,activity关闭时需要关闭当前float            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;        } else {            wManager = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {                if (Build.VERSION.SDK_INT > 23) {                    //在android7.1以上系统需要使用TYPE_PHONE类型 配合运行时权限                    wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;                } else {                    wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;                }            } else {                wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;            }        }        mScreenWidth = wManager.getDefaultDisplay().getWidth();        int screenHeigth = wManager.getDefaultDisplay().getHeight();        //判断状态栏是否显示 如果不显示则statusBarHeight为0        mStatusBarHeight = dp2Px(25, mActivity);        wmParams.format = PixelFormat.RGBA_8888;        wmParams.gravity = Gravity.LEFT | Gravity.TOP;        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;        mHintLocation = getSetting(LOCATION_X, mDefaultLocation);        int defaultY = ((screenHeigth - mStatusBarHeight) / 2) / 3;        int y = getSetting(LOCATION_Y, defaultY);        if (mHintLocation == LEFT) {            wmParams.x = 0;        } else {            wmParams.x = mScreenWidth;        }        if (y != 0 && y != defaultY) {            wmParams.y = y;        } else {            wmParams.y = defaultY;        }        wmParams.alpha = 1;        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;    }    /**     * 初始化悬浮球     */    private void initFloat() {        genarateLeftLineLayout();        genarateRightLineLayout();        mFloatLogo = new DotImageView(mActivity, mLogoRes);        mFloatLogo.setLayoutParams(new WindowManager.LayoutParams(dp2Px(50, mActivity), dp2Px(50, mActivity)));        mFloatLogo.setDrawNum(mDrawRedPointNum);        mFloatLogo.setBgColor(mBackMenuColor);        mFloatLogo.setDrawDarkBg(true);        caculateDotNum();        floatBtnEvent();        try {            wManager.addView(mFloatLogo, wmParams);        } catch (Exception e) {            e.printStackTrace();        }    }    private void genarateLeftLineLayout() {        DotImageView floatLogo = new DotImageView(mActivity, mLogoRes);        floatLogo.setLayoutParams(new WindowManager.LayoutParams(dp2Px(50, mActivity), dp2Px(50, mActivity)));        floatLogo.setDrawNum(mDrawRedPointNum);        floatLogo.setDrawDarkBg(false);        rootView = new LinearLayout(mActivity);        rootView.setOrientation(LinearLayout.HORIZONTAL);        rootView.setGravity(Gravity.CENTER);        rootView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dp2Px(50, mActivity)));        rootView.setBackgroundDrawable(mBackground);        FloatMenuView mFloatMenuView = new FloatMenuView.Builder(mActivity)                .setFloatItems(mFloatItems)                .setBackgroundColor(Color.TRANSPARENT)                .setCicleBg(mCicleMenuBg)                .setStatus(FloatMenuView.STATUS_LEFT)                .setMenuBackgroundColor(Color.TRANSPARENT)                .drawNum(mDrawRedPointNum)                .create();        setMenuClickListener(mFloatMenuView);        rootView.addView(floatLogo);        rootView.addView(mFloatMenuView);        floatLogo.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (isExpaned) {                    try {                        wManager.removeViewImmediate(rootView);                        wManager.addView(FloatLogoMenu.this.mFloatLogo, wmParams);                    } catch (Exception e) {                        e.printStackTrace();                    }                    isExpaned = false;                }            }        });    }    private void genarateRightLineLayout() {        final DotImageView floatLogo = new DotImageView(mActivity, mLogoRes);        floatLogo.setLayoutParams(new WindowManager.LayoutParams(dp2Px(50, mActivity), dp2Px(50, mActivity)));        floatLogo.setDrawNum(mDrawRedPointNum);        floatLogo.setDrawDarkBg(false);        floatLogo.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (isExpaned) {                    try {                        wManager.removeViewImmediate(rootViewRight);                        wManager.addView(FloatLogoMenu.this.mFloatLogo, wmParams);                    } catch (Exception e) {                        e.printStackTrace();                    }                    isExpaned = false;                }            }        });        rootViewRight = new LinearLayout(mActivity);        rootViewRight.setOrientation(LinearLayout.HORIZONTAL);        rootViewRight.setGravity(Gravity.CENTER);        rootViewRight.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dp2Px(50, mActivity)));        rootViewRight.setBackgroundDrawable(mBackground);        FloatMenuView mFloatMenuView = new FloatMenuView.Builder(mActivity)                .setFloatItems(mFloatItems)                .setBackgroundColor(Color.TRANSPARENT)                .setCicleBg(mCicleMenuBg)                .setStatus(FloatMenuView.STATUS_RIGHT)                .setMenuBackgroundColor(Color.TRANSPARENT)                .drawNum(mDrawRedPointNum)                .create();        setMenuClickListener(mFloatMenuView);        rootViewRight.addView(mFloatMenuView);        rootViewRight.addView(floatLogo);    }    /**     * 初始化 隐藏悬浮球的定时器     */    private void initTimer() {        mHideTimer = new CountDownTimer(2000, 10) {        //悬浮窗超过5秒没有操作的话会自动隐藏            @Override            public void onTick(long millisUntilFinished) {                if (isExpaned) {                    mHideTimer.cancel();                }            }            @Override            public void onFinish() {                if (isExpaned) {                    mHideTimer.cancel();                    return;                }                if (!isDraging) {                    if (mHintLocation == LEFT) {                        mFloatLogo.setStatus(DotImageView.HIDE_LEFT);                        mFloatLogo.setDrawDarkBg(true);                    } else {                        mFloatLogo.setStatus(DotImageView.HIDE_RIGHT);                        mFloatLogo.setDrawDarkBg(true);                    }//                    mFloatLogo.setOnTouchListener(mDefaultOnTouchListerner);//把onClick事件分发下去,防止onclick无效                }            }        };    }    /**     * 用于 拦截 菜单项的 关闭事件,以方便开始 隐藏定时器     *     * @param mFloatMenuView     */    private void setMenuClickListener(FloatMenuView mFloatMenuView) {        mFloatMenuView.setOnMenuClickListener(new FloatMenuView.OnMenuClickListener() {            @Override            public void onItemClick(int position, String title) {                mOnMenuClickListener.onItemClick(position, title);            }            @Override            public void dismiss() {                mFloatLogo.setDrawDarkBg(true);                mOnMenuClickListener.dismiss();                mHideTimer.start();            }        });    }    /**     * 悬浮窗的点击事件和touch事件的切换     */    private void floatBtnEvent() {        //这里的onCick只有 touchListener = mDefaultOnTouchListerner 才会触发//        mFloatLogo.setOnClickListener(new OnClickListener() {//            @Override//            public void onClick(View v) {//                if (!isDraging) {//                    if (mFloatLogo.getStatus() != DotImageView.NORMAL) {//                        mFloatLogo.setBitmap(mLogoRes);//                        mFloatLogo.setStatus(DotImageView.NORMAL);//                        if (!mFloatLogo.mDrawDarkBg) {//                            mFloatLogo.setDrawDarkBg(true);//                        }//                    }//                    mFloatLogo.setOnTouchListener(touchListener);//                    mHideTimer.start();//                }//            }//        });        mFloatLogo.setOnTouchListener(touchListener);//恢复touch事件    }    /**     * 悬浮窗touch事件的 down 事件     */    private void floatEventDown(MotionEvent event) {        isDraging = false;        mHideTimer.cancel();        if (mFloatLogo.getStatus() != DotImageView.NORMAL) {            mFloatLogo.setStatus(DotImageView.NORMAL);        }        if (!mFloatLogo.mDrawDarkBg) {            mFloatLogo.setDrawDarkBg(true);        }        if (mFloatLogo.getStatus() != DotImageView.NORMAL) {            mFloatLogo.setStatus(DotImageView.NORMAL);        }        mXInView = event.getX();        mYinview = event.getY();        mXDownInScreen = event.getRawX();        mYDownInScreen = event.getRawY();        mXInScreen = event.getRawX();        mYInScreen = event.getRawY();    }    /**     * 悬浮窗touch事件的 move 事件     */    private void floatEventMove(MotionEvent event) {        mXInScreen = event.getRawX();        mYInScreen = event.getRawY();        //连续移动的距离超过3则更新一次视图位置        if (Math.abs(mXInScreen - mXDownInScreen) > mFloatLogo.getWidth() / 4 || Math.abs(mYInScreen - mYDownInScreen) > mFloatLogo.getWidth() / 4) {            wmParams.x = (int) (mXInScreen - mXInView);            wmParams.y = (int) (mYInScreen - mYinview) - mFloatLogo.getHeight() / 2;            updateViewPosition(); // 手指移动的时候更新小悬浮窗的位置            double a = mScreenWidth / 2;            float offset = (float) ((a - (Math.abs(wmParams.x - a))) / a);            mFloatLogo.setDraging(isDraging, offset, false);        } else {            isDraging = false;            mFloatLogo.setDraging(false, 0, true);        }    }    /**     * 悬浮窗touch事件的 up 事件     */    private void floatEventUp() {        if (mXInScreen < mScreenWidth / 2) {   //在左边            mHintLocation = LEFT;        } else {                   //在右边            mHintLocation = RIGHT;        }        if (valueAnimator == null) {            valueAnimator = ValueAnimator.ofInt(64);            valueAnimator.setInterpolator(mLinearInterpolator);            valueAnimator.setDuration(1000);            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    mResetLocationValue = (int) animation.getAnimatedValue();                    mHandler.post(updatePositionRunnable);                }            });            valueAnimator.addListener(new Animator.AnimatorListener() {                @Override                public void onAnimationStart(Animator animation) {                }                @Override                public void onAnimationEnd(Animator animation) {                    if (Math.abs(wmParams.x) < 0) {                        wmParams.x = 0;                    } else if (Math.abs(wmParams.x) > mScreenWidth) {                        wmParams.x = mScreenWidth;                    }                    updateViewPosition();                    isDraging = false;                    mFloatLogo.setDraging(false, 0, true);                    mHideTimer.start();                }                @Override                public void onAnimationCancel(Animator animation) {                    if (Math.abs(wmParams.x) < 0) {                        wmParams.x = 0;                    } else if (Math.abs(wmParams.x) > mScreenWidth) {                        wmParams.x = mScreenWidth;                    }                    updateViewPosition();                    isDraging = false;                    mFloatLogo.setDraging(false, 0, true);                    mHideTimer.start();                }                @Override                public void onAnimationRepeat(Animator animation) {                }            });        }        if (!valueAnimator.isRunning()) {            valueAnimator.start();        }//        //这里需要判断如果如果手指所在位置和logo所在位置在一个宽度内则不移动,        if (Math.abs(mXInScreen - mXDownInScreen) > mFloatLogo.getWidth() / 5 || Math.abs(mYInScreen - mYDownInScreen) > mFloatLogo.getHeight() / 5) {            isDraging = false;        } else {            openMenu();        }    }    /**     * 用于检查并更新悬浮球的位置     */    private void checkPosition() {        if (wmParams.x > 0 && wmParams.x < mScreenWidth) {            if (mHintLocation == LEFT) {                wmParams.x = wmParams.x - mResetLocationValue;            } else {                wmParams.x = wmParams.x + mResetLocationValue;            }            updateViewPosition();            double a = mScreenWidth / 2;            float offset = (float) ((a - (Math.abs(wmParams.x - a))) / a);            mFloatLogo.setDraging(isDraging, offset, true);            return;        }        if (Math.abs(wmParams.x) < 0) {            wmParams.x = 0;        } else if (Math.abs(wmParams.x) > mScreenWidth) {            wmParams.x = mScreenWidth;        }        if (valueAnimator.isRunning()) {            valueAnimator.cancel();        }        updateViewPosition();        isDraging = false;    }    /**     * 打开菜单     */    private void openMenu() {        if (isDraging) return;        if (!isExpaned) {            mFloatLogo.setDrawDarkBg(false);            try {                wManager.removeViewImmediate(mFloatLogo);                if (mHintLocation == RIGHT) {                    wManager.addView(rootViewRight, wmParams);                } else {                    wManager.addView(rootView, wmParams);                }            } catch (Exception e) {                e.printStackTrace();            }            isExpaned = true;            mHideTimer.cancel();        } else {            mFloatLogo.setDrawDarkBg(true);            if (isExpaned) {                try {                    wManager.removeViewImmediate(mHintLocation == LEFT ? rootView : rootViewRight);                    wManager.addView(mFloatLogo, wmParams);                } catch (Exception e) {                    e.printStackTrace();                }                isExpaned = false;            }            mHideTimer.start();        }    }    /**     * 更新悬浮窗在屏幕中的位置。     */    private void updateViewPosition() {        isDraging = true;        try {            if (!isExpaned) {                if (wmParams.y - mFloatLogo.getHeight() / 2 <= 0) {                    wmParams.y = mStatusBarHeight;                    isDraging = true;                }                wManager.updateViewLayout(mFloatLogo, wmParams);            }        } catch (Exception e) {            e.printStackTrace();        }    }    public void show() {        try {            if (wManager != null && wmParams != null && mFloatLogo != null) {                wManager.addView(mFloatLogo, wmParams);            }            if (mHideTimer != null) {                mHideTimer.start();            } else {                initTimer();                mHideTimer.start();            }        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 关闭菜单     */    public void hide() {        destoryFloat();    }    /**     * 移除所有悬浮窗 释放资源     */    public void destoryFloat() {        //记录上次的位置logo的停放位置,以备下次恢复        saveSetting(LOCATION_X, mHintLocation);        saveSetting(LOCATION_Y, wmParams.y);        mFloatLogo.clearAnimation();        try {            mHideTimer.cancel();            if (isExpaned) {                wManager.removeViewImmediate(mHintLocation == LEFT ? rootView : rootViewRight);            } else {                wManager.removeViewImmediate(mFloatLogo);            }            isExpaned = false;            isDraging = false;        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 计算总红点数     */    private void caculateDotNum() {        int dotNum = 0;        for (FloatItem floatItem : mFloatItems) {            if (!TextUtils.isEmpty(floatItem.getDotNum())) {                int num = Integer.parseInt(floatItem.getDotNum());                dotNum = dotNum + num;            }        }        mFloatLogo.setDrawNum(mDrawRedPointNum);        setDotNum(dotNum);    }    /**     * 绘制悬浮球的红点     *     * @param dotNum d     */    private void setDotNum(int dotNum) {        mFloatLogo.setDotNum(dotNum, new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {                if (!isDraging) {                    mHideTimer.start();                }            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });    }    /**     * 用于暴露给外部判断是否包含某个菜单项     *     * @param menuLabel string     * @return boolean     */    public boolean hasMenu(String menuLabel) {        for (FloatItem menuItem : mFloatItems) {            if (TextUtils.equals(menuItem.getTitle(), menuLabel)) {                return true;            }        }        return false;    }    /**     * 用于保存悬浮球的位置记录     *     * @param key          String     * @param defaultValue int     * @return int     */    private int getSetting(String key, int defaultValue) {        try {            SharedPreferences sharedata = mActivity.getSharedPreferences("floatLogo", 0);            return sharedata.getInt(key, defaultValue);        } catch (Exception e) {            e.printStackTrace();        }        return defaultValue;    }    /**     * 用于保存悬浮球的位置记录     *     * @param key   String     * @param value int     */    public void saveSetting(String key, int value) {        try {            SharedPreferences.Editor sharedata = mActivity.getSharedPreferences("floatLogo", 0).edit();            sharedata.putInt(key, value);            sharedata.apply();        } catch (Exception e) {            e.printStackTrace();        }    }    public static int dp2Px(float dp, Context mContext) {        return (int) TypedValue.applyDimension(                TypedValue.COMPLEX_UNIT_DIP,                dp,                mContext.getResources().getDisplayMetrics());    }    public interface OnMenuClickListener {        void onMenuExpended(boolean isExpened);    }    public void setValueAnimator() {    }    public static final class Builder {        private int mBackMenuColor;        private boolean mDrawRedPointNum;        private boolean mCicleMenuBg;        private Bitmap mLogoRes;        private int mDefaultLocation;        private List mFloatItems = new ArrayList<>();        private Context mActivity;        private FloatMenuView.OnMenuClickListener mOnMenuClickListener;        private Drawable mDrawable;        public Builder setBgDrawable(Drawable drawable) {            mDrawable = drawable;            return this;        }        public Builder() {        }        public Builder setFloatItems(List mFloatItems) {            this.mFloatItems = mFloatItems;            return this;        }        public Builder addFloatItem(FloatItem floatItem) {            this.mFloatItems.add(floatItem);            return this;        }        public Builder backMenuColor(int val) {            mBackMenuColor = val;            return this;        }        public Builder drawRedPointNum(boolean val) {            mDrawRedPointNum = val;            return this;        }        public Builder drawCicleMenuBg(boolean val) {            mCicleMenuBg = val;            return this;        }        public Builder logo(Bitmap val) {            mLogoRes = val;            return this;        }        public Builder withActivity(Activity val) {            mActivity = val;            return this;        }        public Builder withContext(Context val) {            mActivity = val;            return this;        }        public Builder setOnMenuItemClickListener(FloatMenuView.OnMenuClickListener val) {            mOnMenuClickListener = val;            return this;        }        public Builder defaultLocation(int val) {            mDefaultLocation = val;            return this;        }        public FloatLogoMenu showWithListener(FloatMenuView.OnMenuClickListener val) {            mOnMenuClickListener = val;            return new FloatLogoMenu(this);        }        public FloatLogoMenu showWithLogo(Bitmap val) {            mLogoRes = val;            return new FloatLogoMenu(this);        }        public FloatLogoMenu show() {            return new FloatLogoMenu(this);        }    }}

FloatMenuView.java

package com.yw.game.floatmenu;import android.animation.Animator;import android.animation.ObjectAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.PointF;import android.graphics.Rect;import android.graphics.RectF;import android.text.TextUtils;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;/** * Created by wengyiming on 2017/7/21. */public class FloatMenuView extends View {    public static final int STATUS_LEFT = 3;//展开左边菜单    public static final int STATUS_RIGHT = 4;//展开右边菜单    private int mStatus = STATUS_RIGHT;//默认右边    private Paint mPaint;//画笔    private int mBackgroundColor = 0x00FFFFFF;//默认背景颜色 完全透明的白色    private int mMenuBackgroundColor = -1;//菜单的背景颜色    private RectF mBgRect;//菜单的背景矩阵    private int mItemWidth = dip2px(50);//菜单项的宽度    private int mItemHeight = dip2px(50);//菜单项的高度    private int mItemLeft = 0;//菜单项左边的默认偏移值,这里是0    private int mCorner = dip2px(2);//菜单背景的圆角多出的宽度    private int mRadius = dip2px(4);//红点消息半径    private final int mRedPointRadiuWithNoNum = dip2px(3);//红点圆半径    private int mFontSizePointNum = sp2px(10);//红点消息数字的文字大小    private int mFontSizeTitle = sp2px(12);//菜单项的title的文字大小    private float mFirstItemTop;//菜单项的最小y值,上面起始那条线    private boolean mDrawNum = false;//是否绘制数字,false则只绘制红点    private boolean cicleBg = false;//菜单项背景是否绘制成圆形,false则绘制矩阵    private List mItemList = new ArrayList<>();//菜单项的内容    private List mItemRectList = new ArrayList<>();//菜单项所占用位置的记录,用于判断点击事件    private OnMenuClickListener mOnMenuClickListener;//菜单项的点击事件回调    private ObjectAnimator mAlphaAnim;//消失关闭动画的透明值    //设置菜单内容集合    public void setItemList(List itemList) {        mItemList = itemList;    }    //设置是否绘制红点数字    public void drawNum(boolean drawNum) {        mDrawNum = drawNum;    }    //设置是否绘制圆形菜单,否则矩阵    public void setCicleBg(boolean cicleBg) {        this.cicleBg = cicleBg;    }    //用于标记所依赖的view的screen的坐标,实际view的坐标是window坐标,所以这里后面会减去状态栏的高度    //设置菜单的背景颜色    public void setMenuBackgroundColor(int mMenuBackgroundColor) {        this.mMenuBackgroundColor = mMenuBackgroundColor;    }    //设置这个view(整个屏幕)的背景,这里默认透明    public void setBackgroundColor(int BackgroundColor) {        this.mBackgroundColor = BackgroundColor;    }    //下面开始的注释我写不动了,看不懂的话请自行领悟吧    public FloatMenuView(Context context) {        super(context);    }    public FloatMenuView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public FloatMenuView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public FloatMenuView(Context baseContext,  int status) {        super(baseContext);        mStatus = status;        int screenWidth = getResources().getDisplayMetrics().widthPixels;        int screenHeight = getResources().getDisplayMetrics().heightPixels;        mBgRect = new RectF(0, 0, screenWidth, screenHeight);        initView();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(mItemWidth * mItemList.size(), mItemHeight);    }    private void initView( ) {        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setStyle(Paint.Style.FILL);        mPaint.setTextSize(sp2px(12));        mAlphaAnim = ObjectAnimator.ofFloat(this, "alpha", 1.0f, 0f);        mAlphaAnim.setDuration(50);        mAlphaAnim.addListener(new MyAnimListener() {            @Override            public void onAnimationEnd(Animator animation) {                if (mOnMenuClickListener != null) {                    removeView();                    mOnMenuClickListener.dismiss();                }            }        });        mFirstItemTop = 0;        if (mStatus == STATUS_LEFT) {            mItemLeft = 0;        } else {            mItemLeft = 0;        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        switch (mStatus) {            case STATUS_LEFT:                drawBackground(canvas);                drawFloatLeftItem(canvas);                break;            case STATUS_RIGHT:                drawBackground(canvas);                drawFloatLeftItem(canvas);                break;        }    }    private void drawBackground(Canvas canvas) {        mPaint.setColor(mBackgroundColor);        canvas.drawRect(mBgRect, mPaint);    }    private void drawFloatLeftItem(Canvas canvas) {        mItemRectList.clear();        for (int i = 0; i < mItemList.size(); i++) {            canvas.save();            mPaint.setColor(mMenuBackgroundColor);            if (cicleBg) {                float cx = (mItemLeft + i * mItemWidth) + mItemWidth / 2;//x中心点                float cy = mFirstItemTop + mItemHeight / 2;//y中心点                float radius = mItemWidth / 2;//半径                canvas.drawCircle(cx, cy, radius, mPaint);            } else {                mPaint.setColor(mItemList.get(i).bgColor);                canvas.drawRect(mItemLeft + i * mItemWidth, mFirstItemTop, mItemLeft + mItemWidth + i * mItemWidth, mFirstItemTop + mItemHeight, mPaint);            }            mItemRectList.add(new RectF(mItemLeft + i * mItemWidth, mFirstItemTop, mItemLeft + mItemWidth + i * mItemWidth, mFirstItemTop + mItemHeight));            mPaint.setColor(mItemList.get(i).bgColor);            drawIconTitleDot(canvas, i);        }        canvas.restore();    }    private void drawIconTitleDot(Canvas canvas, int position) {        FloatItem floatItem = mItemList.get(position);        if (floatItem.icon != null) {            float centryX = mItemLeft + mItemWidth / 2 + (mItemWidth) * position;//计算每一个item的中心点x的坐标值            float centryY = mFirstItemTop + mItemHeight / 2;//计算每一个item的中心点的y坐标值            float left = centryX - mItemWidth / 4;//计算icon的左坐标值 中心点往左移宽度的四分之一            float right = centryX + mItemWidth / 4;            float iconH = mItemHeight * 0.5f;//计算出icon的宽度 = icon的高度            float textH = getTextHeight(floatItem.getTitle(), mPaint);            float paddH = (mItemHeight - iconH - textH - mRadius) / 2;//总高度减去文字的高度,减去icon高度,再除以2就是上下的间距剩余            float top = centryY - mItemHeight / 2 + paddH;//计算icon的上坐标值            float bottom = top + iconH;//剩下的高度空间用于画文字            //画icon            mPaint.setColor(floatItem.titleColor);            canvas.drawBitmap(floatItem.icon, null, new RectF(left, top, right, bottom), mPaint);            if (!TextUtils.isEmpty(floatItem.dotNum) && !floatItem.dotNum.equals("0")) {                float dotLeft = centryX + mItemWidth / 5;                float cx = dotLeft + mCorner;//x中心点                float cy = top + mCorner;//y中心点                int radiu = mDrawNum ? mRadius : mRedPointRadiuWithNoNum;                //画红点                mPaint.setColor(Color.RED);                canvas.drawCircle(cx, cy, radiu, mPaint);                if (mDrawNum) {                    mPaint.setColor(Color.WHITE);                    mPaint.setTextSize(mFontSizePointNum);                    //画红点消息数                    canvas.drawText(floatItem.dotNum, cx - getTextWidth(floatItem.getDotNum(), mPaint) / 2, cy + getTextHeight(floatItem.getDotNum(), mPaint) / 2, mPaint);                }            }            mPaint.setColor(floatItem.titleColor);            mPaint.setTextSize(mFontSizeTitle);            //画menu title            canvas.drawText(floatItem.title, centryX - getTextWidth(floatItem.getTitle(), mPaint) / 2, centryY + iconH / 2 + getTextHeight(floatItem.getTitle(), mPaint) / 2, mPaint);        }    }    public void startAnim() {        if (mItemList.size() == 0) {            return;        }        invalidate();    }    public void dismiss() {        if (!mAlphaAnim.isRunning()) {            mAlphaAnim.start();        }    }    private void removeView() {        ViewGroup vg = (ViewGroup) this.getParent();        if (vg != null) {            vg.removeView(this);        }    }    @Override    protected void onWindowVisibilityChanged(int visibility) {        if (visibility == GONE) {            if (mOnMenuClickListener != null) {                mOnMenuClickListener.dismiss();            }        }        super.onWindowVisibilityChanged(visibility);    }    public void setOnMenuClickListener(OnMenuClickListener onMenuClickListener) {        this.mOnMenuClickListener = onMenuClickListener;    }    public interface OnMenuClickListener {        void onItemClick(int position, String title);        void dismiss();    }    private abstract class MyAnimListener implements Animator.AnimatorListener {        @Override        public void onAnimationStart(Animator animation) {        }        @Override        public void onAnimationCancel(Animator animation) {        }        @Override        public void onAnimationRepeat(Animator animation) {        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                for (int i = 0; i < mItemRectList.size(); i++) {                    if (mOnMenuClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {                        mOnMenuClickListener.onItemClick(i, mItemList.get(i).title);                        return true;                    }                }                dismiss();        }        return false;    }    private boolean isPointInRect(PointF pointF, RectF targetRect) {        return pointF.x >= targetRect.left && pointF.x <= targetRect.right && pointF.y >= targetRect.top && pointF.y <= targetRect.bottom;    }    public static class Builder {        private Context mActivity;        private List mFloatItems = new ArrayList<>();        private int mBgColor = Color.TRANSPARENT;        private int mStatus = STATUS_LEFT;        private boolean cicleBg = false;        private int mMenuBackgroundColor = -1;        private boolean mDrawNum = false;        public Builder drawNum(boolean drawNum) {            mDrawNum = drawNum;            return this;        }        public Builder setMenuBackgroundColor(int mMenuBackgroundColor) {            this.mMenuBackgroundColor = mMenuBackgroundColor;            return this;        }        public Builder setCicleBg(boolean cicleBg) {            this.cicleBg = cicleBg;            return this;        }        public Builder setStatus(int status) {            mStatus = status;            return this;        }        public Builder setFloatItems(List floatItems) {            this.mFloatItems = floatItems;            return this;        }        public Builder(Context activity ) {            mActivity = activity;        }        public Builder addItem(FloatItem floatItem) {            mFloatItems.add(floatItem);            return this;        }        public Builder addItems(List list) {            mFloatItems.addAll(list);            return this;        }        public Builder setBackgroundColor(int color) {            mBgColor = color;            return this;        }        public FloatMenuView create() {            FloatMenuView floatMenuView = new FloatMenuView(mActivity, mStatus);            floatMenuView.setItemList(mFloatItems);            floatMenuView.setBackgroundColor(mBgColor);            floatMenuView.setCicleBg(cicleBg);            floatMenuView.startAnim();            floatMenuView.drawNum(mDrawNum);            floatMenuView.setMenuBackgroundColor(mMenuBackgroundColor);            return floatMenuView;        }    }    private int dip2px(float dipValue) {        final float scale = getContext().getResources().getDisplayMetrics().density;        return (int) (dipValue * scale + 0.5f);    }    private int sp2px(float spValue) {        final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;        return (int) (spValue * fontScale + 0.5f);    }    private float getTextHeight(String text, Paint paint) {        Rect rect = new Rect();        paint.getTextBounds(text, 0, text.length(), rect);        return rect.height() / 1.1f;    }    private float getTextWidth(String text, Paint paint) {        return paint.measureText(text);    }}

Utils.java

package com.yw.game.floatmenu;import android.content.Context;import android.util.TypedValue;import android.view.ViewGroup;import android.view.WindowManager;import android.view.animation.AccelerateInterpolator;import android.view.animation.AlphaAnimation;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.LinearInterpolator;import android.view.animation.ScaleAnimation;import android.widget.FrameLayout;import java.lang.reflect.Field;public class Utils {    private static int statusBarHeight;    /**     * 用于获取状态栏的高度。     *     * @return 返回状态栏高度的像素值。     */    public static int getStatusBarHeight(Context context) {        if (statusBarHeight == 0) {            try {                Class<?> c = Class.forName("com.android.internal.R$dimen");                Object o = c.newInstance();                Field field = c.getField("status_bar_height");                int x = (Integer) field.get(o);                statusBarHeight = context.getResources().getDimensionPixelSize(x);            } catch (Exception e) {                e.printStackTrace();            }        }        return statusBarHeight;    }}

更多相关文章

  1. android Dialog中SeekBar的使用方法
  2. android中opengl es基本方法使用说明
  3. 程序员也是会浪漫的->打造浪漫的Android表白程序
  4. Android--边距(margin)与内边距(padding)
  5. android为图片生成缩略图
  6. Android(安卓)小说阅读护眼模式
  7. Android中的硬件加速
  8. android 超简单的拖动按钮 悬浮按钮 吸附按钮
  9. android2.3 鼠标输入集成

随机推荐

  1. Android(安卓)桥接模式
  2. 关于android framework相关的一些看法之-
  3. Android程序员必备的六大顶级开发工具!!!
  4. 仿微信、短信、QQ等消息数目右上角红色小
  5. Android(安卓)--- App列表之分组ListView
  6. 基于树结构的任意层级列表
  7. android屏幕适配,除了使用dp,还可以使用比
  8. Android用Broadcast实现EventBus的功能和
  9. android apk 加固
  10. Android应用程序的编译流程及使用Ant编译