windowmanager的奇技淫巧

android界面編程方面有兩大核心,一個是View代表的界面元素,一個是WindowManager代表的界面管理.前者為卒子,后者為將帥.

基礎

一切view,在界面最終以Window形式展現,被WindowManager管理.

WindowManager提供有三個方法:添加View、更新View和刪除View.

   public void addView(View view, ViewGroup.LayoutParams params);  
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);  
    public void removeView(View view);  

View的展現規則封裝在LayoutParams中,其內部屬性見:

WindowManager.LayoutParams詳解

LayoutParams 主要的幾個屬性

flag

標識這個window怎么響應事件,怎樣的一個透明度,以及一些全屏,鎖屏顯示等等.

WindowManager.LayoutParams的各種flag含義

type

類似于前端里的z-index.值越大越在上面.
type的真正含義: 類型-->根據值的范圍將window分成三大類:

  • 系統級窗口(System windows):
    ranging from FIRST_SYSTEM_WINDOW to LAST_SYSTEM_WINDOW 2000-2999
    可以在任何地方顯示
  • 應用級窗口(Application windows):
    ranging from FIRST_APPLICATION_WINDOW to LAST_APPLICATION_WINDOW 1-99
    典型的: activity
  • 子窗口(Sub-windows):
    ranging from FIRST_SUB_WINDOW to LAST_SUB_WINDOW 1000-1999
    必須依附于某一個應用級窗口

WindowManager.LayoutParams.type的使用
WindowManager.LayoutParams.type屬性

系統內置的窗口實現

  • popupwindow
  • dialog
  • activity
  • toast
  • notification

系統級窗口,6.0以前的權限

一般來說,彈出系統級窗口需要申請android.permission.SYSTEM_ALERT_WINDOW權限,
但是,TYPE_TOAST雖然是系統級窗口,不用申請
然而,國產rom,比如MIUI,會強制要求申請此權限,更鬧心的是,還默認關閉這個權限.
所以,需要兼顧6.0以前的權限申請,以及適配:

https://github.com/hss01248/FloatWindowPermission

奇技淫巧

需求1

在屏幕上顯示一個浮動控件。需要能接收點擊事件,還要能顯示在statusBar(狀態欄)之上,不能被狀態欄遮住

來自 WindowManager的那些蛋疼的事

            WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
            PixelFormat.TRANSLUCENT);

需求2

偷偷地拍照:

  • 思路1:彈出一個透明的activity,這個activity還要能夠不攔截任何事件,屏幕的所有觸摸都要能夠傳遞到下層activity.
    攔路虎: 對activity的許多flag設置會無效,主要是activity無法設置不攔截事件.
  • 思路2: 彈出一個type = TYPE_TOAST的窗口,1平方像素.

代碼庫見此: https://github.com/hss01248/HiddenCamera

核心代碼:

        final WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        PhotoCallback callback2 = new PhotoCallback() {
            @Override
            public void onFail() {
                callback.onFail();
                windowManager.removeView(page.getRootView());
            }

            @Override
            public void onSuccess(String path) {
                callback.onSuccess(path);
                windowManager.removeView(page.getRootView());
            }
        };
        page.setCallback(callback2);
      WindowManager.LayoutParams params =  new WindowManager.LayoutParams();//dialog.getWindow().getAttributes();
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                |WindowManager.LayoutParams.FLAG_DIM_BEHIND//后面變暗
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.gravity = Gravity.LEFT| Gravity.TOP;
        params.dimAmount = 0;//后面變暗區域透明...
        windowManager.addView(page.getRootView(),params);

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容