Android | WindowManger realizes desktop floating window

If you want to realize a floating window displayed on the desktop, you can no longer use Dialog, PopupWindow, etc. They are basically displayed on it. If you want to realize the floating window effect displayed on the desktop, you need to use it realize it.ToastActivityWindowManager

renderings

insert image description here

Implemented using WindowManager

  • Add a floating window:
        sys_view = new SmallWindowView(mContext);
        sys_view.setText("50%");
        sys_view.setOnTouchListener(this);
        windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        int screenWidth = 0, screenHeight = 0;
        if (windowManager != null) {
            //获取屏幕的宽和高
            Point point = new Point();
            windowManager.getDefaultDisplay().getSize(point);
            screenWidth = point.x;
            screenHeight = point.y;
            layoutParams = new WindowManager.LayoutParams();
//            layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
//            layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
            layoutParams.width = 200;
            layoutParams.height = 200;
            //设置type
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //26及以上必须使用TYPE_APPLICATION_OVERLAY   @deprecated TYPE_PHONE
                layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            } else {
                layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
            }
            //设置flags
            layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            layoutParams.gravity = Gravity.START | Gravity.TOP;
            //背景设置成透明
            layoutParams.format = PixelFormat.TRANSPARENT;
            layoutParams.x = screenWidth;
            layoutParams.y = screenHeight / 2;
            //将View添加到屏幕上
            windowManager.addView(sys_view, layoutParams);
        }
  • Update the floating window position:
windowManager.updateViewLayout(sys_view, layoutParams);
  • Close the floating window:
windowManager.removeView(sys_view);

Through the above code, a desktop floating window function can be realized.

Note : In 6.0the above, you need to Manifest.xmldeclare the permission in <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />and dynamically judge the permission when you open the floating window. If you don’t have this permission, you need to jump to the settings page to set it. See the description of the official document:

insert image description here

analyze

1. Add floating window: By Context.getSystemService(Context.WINDOW_SERVICE)obtaining one WindowManager( hereinafter referred to as VM ), VMit is the entrance of external access Window, Activity, Dialog, Toastand other views are attached to Windowit, Windowand it is Viewthe direct manager, VMinherited from ViewManager, its add, refresh, delete methods Also from ViewManager:

public interface ViewManager
{
    
       public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

VMThere is a static inner class WindowManager.LayoutParams, Windoweach property of which is set in this inner class:

  • If LayoutParams.TYPETargetSdkVersion<26 , then can be used directly LayoutParams.TYPE_PHONEor LayoutParams.TYPE_SYSTEM_ALERT, when TargetSdkVersion>=26, TYPE_PHONEand TYPE_SYSTEM_ALERThave been deprecated, need to use TYPE_APPLICATION_OVERLAYto identify TYPE.
  • The attributes FLAGSrepresented by LayoutParams.FLAGS can be controlled through the display characteristics, and several commonly used characteristics: : Using this flag, the click event can be transmitted to the area other than the floating window, otherwise the event will not be received in other areas. : Indicates that the floating window does not need to get the focus, nor does it need to get various input events, and the events will be passed directly to the lower layer with focus : This mode can be displayed on the lock screen interfaceWindowFLAGSWindowLayoutParams.FLAG_NOT_TOUCH_MODALWindowLayoutParams.FLAG_NOT_FOCUSABLEWindowWindow LayoutParams.FLAG_SHOW_WHEN_LOCKEDWindow
  • LayoutParams.FORMAT The background format of the floating window Window, generally set to PixelFormat.TRANSPARENTtransparent
  • LayoutParams.X & LayoutParams.Y The coordinate value of the floating window Windowon the screen, which can be used X&Yto refresh Windowthe position on the screen according to the value
  • LayoutParams.Width & LayoutParams.HeightWindow The width and height of the floating window

2. Update the position of the floating window: Update the value of and Viewin OnTouchEventor in and reset the position of the floating window Window on the screen, as follows:OnTouchlayoutParams.xlayoutParams.ywindowManager.updateViewLayout()

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int mInScreenX = (int) event.getRawX();
        int mInScreenY = (int) event.getRawY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                layoutParams.x += mInScreenX - mLastX;
                layoutParams.y += mInScreenY - mLastY;
                mLastX = mInScreenX;
                mLastY = mInScreenY;
                windowManager.updateViewLayout(sys_view, layoutParams);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

3. Delete the floating window: It is relatively simple to delete, just call directly to windowManager.removeView(view)delete viewfrom itWindow .

question

When 6.0以上using it, you need to dynamically apply for the permission of the floating window, as follows:

//判断有没有悬浮窗权限,没有去申请
if(!Settings.canDrawOverlays(context)){
    
    
     Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + context.getPackageName()));
     context.startActivityForResult(intent, REQUEST_CODE);
}

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
    
        switch (requestCode) {
    
    
            case REQUEST_CODE:
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
                if (!WindowUtil.canOverDraw(this)) {
    
    
                    toast("悬浮窗权限未开启,请在设置中手动打开");
                    return;
                }
                WindowController.getInstance().showThumbWindow();
                break;
        }
    }

By Settings.canDrawOverlays(context)judging whether there is a floating window permission, if not, jump to the setting page to set it up, and onActivityResult ()get the application result in it, it seems perfect, but in the actual test, it is found that there is a problem with the mobile phone above 8.0, even in the setting Agree to the permissions in the 8.0 mobile phone, Settings.canDrawOverlays(context)it always returns false, but when the page is closed and the method is called again, it returns again true, and it feels that there is a certain delay. googleAfter a while, I found that other people have also encountered this googleproblem bug. .

If you want the full version of Android learning materials, please click to get it for free

Guess you like

Origin blog.csdn.net/m0_71506521/article/details/130424252