模仿魅族flyme自带的悬浮球floatball,通过不同的触摸方式,模拟虚拟按键

觉得魅族的悬浮球做的很不错,主要是简洁方便。于是就自己实现了一下。项目源代码:FloatingBall源代码

主要是解决三个方面的问题:

  1.桌面悬浮窗的实现

  2.设置悬浮球触摸事件(拖动,点击,上下左右滑动)

  2.模拟虚拟按键(返回,home,任务面板,电源键,菜单键等)


   (一)桌面悬浮窗的实现

     通过WindowManager将自定义的悬浮球布局ballview添加到手机屏幕

     

//布局转化成要显示的view
 ballView = LayoutInflater.from(this).inflate(R.layout.floatball, null);

 wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        ballWmParams = new WindowManager.LayoutParams();

//设置悬浮窗的相关参数
        ballWmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        ballWmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        ballWmParams.gravity = Gravity.LEFT | Gravity.TOP;

        ballWmParams.x = MainActivity.sp.getInt("ballWmParamsX",0);
        ballWmParams.y = MainActivity.sp.getInt("ballWmParamsY",0);

        ballWmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        ballWmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        ballWmParams.format = PixelFormat.RGBA_8888;

//将悬浮球view添加到屏幕
 wm.addView(ballView, ballWmParams);

(二)悬浮球触摸事件

    通过设置悬浮球buttton的setOnTouchListener监听触摸事件

   1.拖动悬浮球改变位置

     根据滑动的距离改变WindowManager的ballWmParams.x和ballWmParams.y实现悬浮球的拖动

   2.点击和上下左右滑动

    通过对滑动事件的x,y坐标量变化的分析,判断是点击,还是上下左右滑动

//注册触碰事件监听器
        floatImage.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                x = event.getX();
                y = event.getY();
                if(tag == 0)
                {
                    oldOffsetX = ballWmParams.x;
                    oldOffsetY = ballWmParams.y;
                }

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        ismoving = false;
                        mTouchStartX = (int)event.getX();
                        mTouchStartY = (int)event.getY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        ismoving = true;
                        tag = 1;
                        ballWmParams.x += (int) (x - mTouchStartX)/3;// 减小偏移量,防止过度抖动
                        ballWmParams.y += (int) (y - mTouchStartY)/3;// 减小偏移量,防止过度抖动
                        if(canmove)
                        {
                            updateViewPosition();
                            saveStates("ballWmParamsX", ballWmParams.x);
                            saveStates("ballWmParamsY",ballWmParams.y);
                        }

                        break;
                    case MotionEvent.ACTION_UP:

                        mTouchStartX = mTouchStartY = 0;
                        newOffsetX = ballWmParams.x;
                        newOffsetY = ballWmParams.y;
                        
                        // 点击悬浮球
                        if (Math.abs(oldOffsetX - newOffsetX) <= 20 && Math.abs(oldOffsetY - newOffsetY) <= 20) {
                            onFloatBallClick();
                            onClearOffset();
                        }

                        if(!canmove)
                        {
                            //向上滑动
                            if ((oldOffsetY - newOffsetY) - Math.abs(oldOffsetX - newOffsetX) > 20 && (oldOffsetY - newOffsetY) >20 )
                            {

                                onFloatBallFlipUp();
                            }
                            //向下滑动
                            else if ((newOffsetY - oldOffsetY) - Math.abs(oldOffsetX - newOffsetX) > 20  && (newOffsetY - oldOffsetY) > 20 ){
                                onFloatBallFlipDown();
                            }
                            //向左滑动
                            else if ((oldOffsetX - newOffsetX) - Math.abs(oldOffsetY - newOffsetY) > 20  && (oldOffsetX - newOffsetX) > 20 )
                            {
                                onFloatBallFlipLeft();
                            }
                            //向右滑动
                            else if((newOffsetX - oldOffsetX) - Math.abs(oldOffsetY - newOffsetY) > 20  && (newOffsetX - oldOffsetX) > 20){
                                onFloatBallFlipRight();
                            }
                            onClearOffset();

                        }

                        tag = 0;
                        break;
                }
                //如果拖动则返回false,否则返回true
                if(ismoving == false){
                    return false;
                }else{
                    return true;
                }
            }

        });
 
  (三)模拟虚拟按键

      采用adb shell的input实现,反应速度慢,有延时,效果不好。

      所以采用IWindowManager和InputManager实现模拟按键事件。


 public static void simulateKey(int keyCode) {

        //使用KeyEvent模拟按键按下与弹起
        long l = SystemClock.uptimeMillis();
        KeyEvent localKeyEvent = new KeyEvent(l,l,KeyEvent.ACTION_DOWN,keyCode,0);
        KeyEvent localKeyEvent1 = new KeyEvent(l,l,KeyEvent.ACTION_UP,keyCode,0);

        //判断sdk版本,老版本使用IWindowManager注入按键事件,新版本使用InputManager注入按键事件
        //*******IWindowManager和InputManager都是隐藏类,必须在重新生成sdk中的android.jar,并包含两个类及其依赖*****
        if (Build.VERSION.SDK_INT < 16)
        {
            try {

                IWindowManager.Stub.asInterface(ServiceManager.getService("window")).injectKeyEvent(localKeyEvent, true);
                IWindowManager.Stub.asInterface(ServiceManager.getService("window")).injectKeyEvent(localKeyEvent1, true);
                return;
            } catch (RemoteException e) {
                e.printStackTrace();
                return;
            }
        }

        InputManager.getInstance().injectInputEvent(localKeyEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
        InputManager.getInstance().injectInputEvent(localKeyEvent1, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);


    }


模仿魅族flyme自带的悬浮球floatball,通过不同的触摸方式,模拟虚拟按键_第1张图片            

你可能感兴趣的:(模仿魅族flyme自带的悬浮球floatball,通过不同的触摸方式,模拟虚拟按键)