美文网首页
android_无需权限的浮动窗口

android_无需权限的浮动窗口

作者: 22a5d2ee8385 | 来源:发表于2017-11-14 03:29 被阅读0次
    适用场景:
    
    1.不需要判断Window权限,也许用户不同意权限,窗口会失效
    2.悬浮菜单在APP使用的每一个界面都存(可以选择星的不存在,例如登录页面)
    3.当APP退出时,悬浮菜单会消失
    4.松手悬浮窗口会自动贴边
    
    实现思路:
    https://github.com/153437803/FloatMenu
    
    1.ViewDragHelper,官方提供的一个处理拖拽滑动事件的类库,不明白的可以自行度娘一下
    2.在BaseActivity里面动态判断那些界面需要悬浮窗口,那些界面不需要悬浮窗口, 动态设置布局
    3.在onResume(),onPause(),onBackPressed()根据业务需求,动态判断什么时候需要结束隐藏显示浮动窗口
    
    /**
     * description: 可拖拽的父容器
     * created by kalu on 2017/3/14 15:32
     */
    public class FloatLayout extends FrameLayout {
    
        private final int TEMP_SIZE = DeviceUtil.dp2px(5);
        private final int SCR_WIDTH = DeviceUtil.getScreenWidth();
        private final int SCR_HEIGHT = DeviceUtil.getScreenHeight() - DeviceUtil.getStatusHeight() - DeviceUtil.dp2px(55);
    
        /**********************************************************************************************/
    
        private FloatSub floatSub;
        private ViewDragHelper helper;
    
        /**********************************************************************************************/
    
        private SharedPreferences sp = APP.getInstance().getApplicationContext().getSharedPreferences("FloatLayout", Context.MODE_PRIVATE);
        private SharedPreferences.Editor editor = sp.edit();
        private final String FLOAT_SUB_TOP = "FLOAT_SUB_TOP";
        private final String FLOAT_SUB_LEFT = "FLOAT_SUB_LEFT";
    
        /**********************************************************************************************/
    
        public FloatLayout(Context context) {
            this(context, null, 0);
        }
    
        public FloatLayout(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public FloatLayout(final Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            setBackgroundColor(Color.TRANSPARENT);
    
            floatSub = new FloatSub(APP.getInstance().getApplicationContext());
            floatSub.setVisibility(View.GONE);
            addView(floatSub);
            setFloatSubSize(DeviceUtil.dp2px(168), DeviceUtil.dp2px(100));
    
            helper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
                @Override
                public boolean tryCaptureView(View child, int pointerId) {
    //                Log.e(TAG, "tryCaptureView ==> ");
                    return null == child ? false : child instanceof FloatSub;
                }
    
                /**
                 * 手指触摸水平位移
                 * @param child
                 * @param left
                 * @param dx
                 * @return
                 */
                @Override
                public int clampViewPositionHorizontal(View child, int left, int dx) {
    //                Log.e(TAG, "clampViewPositionHorizontal ==> ");
    
    //                final int leftBound = getPaddingLeft();
    //                final int rightBound = getWidth() - child.getWidth() - leftBound;
    //                final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
    //                return newLeft;
    
                    return left;
                }
    
                /**
                 * 手指触摸竖直位移
                 * @param child
                 * @param top
                 * @param dy
                 * @return
                 */
                @Override
                public int clampViewPositionVertical(View child, int top, int dy) {
    //                Log.e(TAG, "clampViewPositionVertical ==> ");
    
    //                final int topBound = getPaddingTop();
    //                final int bottomBound = getHeight() - child.getHeight() - dp2px(context, 50);
    //                final int newTop = Math.min(Math.max(top, topBound), bottomBound);
    //                return newTop;
    
                    return top;
                }
    
                /**
                 * 水平方向可以滑动的距离
                 * @param child
                 * @return
                 */
                @Override
                public int getViewHorizontalDragRange(View child) {
    //                Log.e(TAG, "getViewHorizontalDragRange ==> ");
    
    //                return getMeasuredWidth() - child.getMeasuredWidth();
                    return getMeasuredWidth();
                }
    
                /**
                 * 竖直方向可以滑动的距离
                 * @param child
                 * @return
                 */
                @Override
                public int getViewVerticalDragRange(View child) {
    //                Log.e(TAG, "getViewVerticalDragRange ==> ");
    
    //                return getMeasuredHeight() - child.getMeasuredHeight() - dp2px(context, 50);
                    return getMeasuredHeight();
                }
    
                @Override
                public void onViewDragStateChanged(int state) {
                    super.onViewDragStateChanged(state);
    
                    if (null == floatSub) return;
                    // 更新坐标
                    float x = floatSub.getX();
                    float y = floatSub.getY();
                    editor.putFloat(FLOAT_SUB_TOP, x);
                    editor.putFloat(FLOAT_SUB_LEFT, y);
                    editor.commit();
                }
    
                @Override
                public void onViewReleased(View releasedChild, float xvel, float yvel) {
    //                Log.e(TAG, "onViewReleased ==> ");
    
                    if (null == floatSub || releasedChild != floatSub) return;
    
                    int width = releasedChild.getWidth();
                    int height = releasedChild.getHeight();
    
                    int left = releasedChild.getLeft();
                    int top = releasedChild.getTop();
                    int right = releasedChild.getRight();
                    int bottom = releasedChild.getBottom();
    
                    // 移到屏幕外边
                    if (left < 0 || top < 0 || right > SCR_WIDTH || bottom > SCR_HEIGHT) {
    
                        // 左侧出边
                        if (left < 0) {
                            left = TEMP_SIZE;
                            if (top < 0) {
                                top = TEMP_SIZE;
                            }
                            if (bottom > SCR_HEIGHT) {
                                top = SCR_HEIGHT - height;
                            }
                        }
                        // 右侧出边
                        else if (right > SCR_WIDTH) {
                            int rightMax = SCR_WIDTH - TEMP_SIZE;
                            left = rightMax - width;
                            if (top < 0) {
                                top = TEMP_SIZE;
                            }
                            if (bottom > SCR_HEIGHT) {
                                top = SCR_HEIGHT - height;
                            }
                        }
                        // 上侧出边
                        else if (top < 0) {
                            top = TEMP_SIZE;
                        }
                        // 下侧出边
                        else if (bottom > SCR_HEIGHT) {
                            top = SCR_HEIGHT - height;
                        }
                    }
                    // 处于屏幕里面
                    else {
    
                        // 距离左侧距离
                        int ragneLeft = left;
                        int ragneRight = SCR_WIDTH - right;
                        int ragneTop = top;
                        int rangeBottom = SCR_HEIGHT - bottom;
    
                        int temp1 = Math.min(ragneLeft, ragneRight);
                        int temp2 = Math.min(temp1, ragneTop);
                        int ragneMin = Math.min(temp2, rangeBottom);
    
                        if (ragneMin == ragneLeft) {
                            left = TEMP_SIZE;
                        } else if (ragneMin == ragneRight) {
                            int rightMax = SCR_WIDTH - TEMP_SIZE;
                            left = rightMax - width;
                        } else if (ragneMin == ragneTop) {
                            top = TEMP_SIZE;
                        } else {
                            top = SCR_HEIGHT - height;
                        }
                    }
    
                    helper.settleCapturedViewAt(left, top);
                    invalidate();
                }
            });
        }
    
        /**********************************************************************************************/
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return helper.shouldInterceptTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            helper.processTouchEvent(event);
            return true;
        }
    
        @Override
        public void computeScroll() {
            if (!helper.continueSettling(true)) return;
            invalidate();
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
    
            if (null != floatSub && floatSub.getVisibility() == View.VISIBLE) {
    
                // 读取保存的位置
                float x = sp.getFloat(FLOAT_SUB_TOP, -1);
                float y = sp.getFloat(FLOAT_SUB_LEFT, -1);
    //            LogUtil.e(TAG, "onLayout ==> x = " + x + ", y = " + y);
    
                if (x == -1 && y == -1) return;
    
                int measuredWidth = floatSub.getMeasuredWidth();
                int maxX = DeviceUtil.getScreenWidth() - measuredWidth - DeviceUtil.dp2px(5);
                if (x > maxX) {
                    x = maxX;
                    sp.edit().putFloat(FLOAT_SUB_TOP, x).commit();
                }
                int measuredHeight = floatSub.getMeasuredHeight();
                int maxY = DeviceUtil.getScreenHeight() - DeviceUtil.dp2px(80) - measuredHeight;
                if (y > maxY) {
                    y = maxY;
                    sp.edit().putFloat(FLOAT_SUB_LEFT, y).commit();
                }
    
                floatSub.layout((int) x, (int) y, (int) x + measuredWidth, (int) y + measuredHeight);
            }
        }
    
        /**********************************************************************************************/
    
        public void clearData() {
            if (null == sp) return;
            sp.edit().clear().commit();
        }
    
        public FloatSub getFloatSub() {
            return floatSub;
        }
    
        public void setFloatSubSize(int width, int height) {
            if (null == floatSub) return;
    
            LayoutParams params = (LayoutParams) floatSub.getLayoutParams();
            params.width = width;
            params.height = height;
            params.gravity = Gravity.RIGHT | Gravity.TOP;
            params.topMargin = DeviceUtil.dp2px(170);
            params.rightMargin = DeviceUtil.dp2px(5);
        }
    
        public void addFloatSub(View view) {
            if (null == floatSub) return;
            floatSub.addView(view, 0);
            floatSub.setVisibility(View.VISIBLE);
        }
    
        public void setOnFloatSubClickListener(OnFloatClickListener listener) {
            if (null == floatSub) return;
            floatSub.setOnFloatClickListener(listener);
        }
    
        /**********************************************************************************************/
    }
    
    /**
     * description: 可拖拽的显示容器
     * created by kalu on 2017/3/14 17:35
     */
    public class FloatSub extends FrameLayout {
    
        private final String TAG = FloatSub.class.getSimpleName();
    
        /**********************************************************************************************/
    
        public FloatSub(Context context) {
            this(context, null, 0);
        }
    
        public FloatSub(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public FloatSub(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            setBackgroundColor(Color.BLACK);
    
            // 1.添加蒙层
            View cover = new View(APP.getInstance().getApplicationContext());
            cover.setClickable(true);
            addView(cover);
            cover.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    if (null == onFloatClickListener) return;
                    onFloatClickListener.onClickFloatWindow(v);
                }
            });
    
            // 2.添加关闭
            ImageView image = new ImageView(APP.getInstance().getApplicationContext());
            image.setClickable(true);
            int pading = DeviceUtil.dp2px(5);
            image.setPadding(pading, pading, pading, pading);
            image.setImageResource(R.drawable.ic_vector_close);
            image.setBackgroundColor(getResources().getColor(R.color.black_40));
            addView(image);
            LayoutParams params = (LayoutParams) image.getLayoutParams();
            int size = DeviceUtil.dp2px(25);
            params.width = size;
            params.height = size;
            params.gravity = Gravity.TOP | Gravity.RIGHT;
            image.setLayoutParams(params);
            image.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    if (null == onFloatClickListener) return;
                    onFloatClickListener.onClickFloatClose();
                }
            });
    
            // 3.添加转圈
            LoadingView loading = new LoadingView(APP.getInstance().getApplicationContext());
            loading.setId(R.id.float_sub_loading);
            loading.setVisibility(View.GONE);
            addView(loading);
            FrameLayout.LayoutParams paramsLoading = (LayoutParams) loading.getLayoutParams();
            paramsLoading.width = DeviceUtil.dp2px(25);
            paramsLoading.height = DeviceUtil.dp2px(25);
            paramsLoading.gravity = Gravity.CENTER;
        }
    
        public void setLoading(int playStatus) {
            LogUtil.e(TAG, "setLoading ==> playStatus = " + playStatus);
    
            View sub = findViewById(R.id.float_sub_loading);
            if (null != sub) {
    
                if (playStatus == PlayerManager.PLAYER_LOADING) {
                    sub.setVisibility(View.VISIBLE);
                    LogUtil.e(TAG, "setLoading ==> 显示");
                } else {
                    sub.setVisibility(View.GONE);
                    LogUtil.e(TAG, "setLoading ==> 隐藏");
                }
            }
        }
    
        /*********************************************************************************************/
    
    //    public void changeLoadingState(int visibility) {
    //        View loading = findViewById(R.id.float_sub_loading);
    //
    //        if (null == loading) return;
    //        loading.setVisibility(visibility);
    //    }
    
        /*********************************************************************************************/
    
        private OnFloatClickListener onFloatClickListener;
    
        public void setOnFloatClickListener(OnFloatClickListener onFloatClickListener) {
            this.onFloatClickListener = onFloatClickListener;
        }
    }
    
    /**
     * Created by SEELE on 2017/3/14.
     */
    
    public interface OnFloatClickListener {
    
        /**
         * 点击孩子
         *
         * @param view
         */
        void onClickFloatWindow(View view);
    
        /**
         * 点击关闭
         */
        void onClickFloatClose();
    }
    

    相关文章

      网友评论

          本文标题:android_无需权限的浮动窗口

          本文链接:https://www.haomeiwen.com/subject/lsxxvxtx.html