天天看點

筆記27 | 通過WindowManager實作懸浮視窗總結 目錄

位址

http://blog.csdn.net/xiangyong_1521/article/details/78401755

目錄

  • 關于Window/WindowManagerService的簡介
  • ViewManager和WindowManager的實作
  • 舉例實作

關于Window/WindowManagerService的簡介

  • WindowManagerService
筆記27 | 通過WindowManager實作懸浮視窗總結 目錄
先來看WindowManagerService,從此圖可以得知,它是位于Framework層的視窗管理服務,職責就是管理系統中的所有視窗,視窗的本質是什麼呢?其實就是一塊顯示區域,在 Android 中就是繪制的畫布:Surface,當一塊 Surface 顯示在螢幕上時,就是使用者所看到的視窗了。WindowManagerService 添加一個視窗的過程,其實就是 WindowManagerService 為其配置設定一塊 Surface 的過程,一塊塊的 Surface 在 WindowManagerService 的管理下有序的排列在螢幕上
  • Window
Window 是一個抽象類,表示一個視窗,它的具體實作類是 PhoneWindow,實作位于 WindowManagerService 中;Window 有三種類型
  1. 應用 Window:應用類 Window 對應一個 Acitivity;
  2. 子 Window :子 Window 不能單獨存在,需要依附在特定的父 Window 中,比如常見的一些 Dialog 就是一個子 Window;
  3. 系統 Window:系統 Window是需要聲明權限才能建立的 Window,比如 Toast 和系統狀态欄都是系統 Window。
Window 是分層的,每個 Window 都有對應的 z-ordered(處在這些疊加視窗中的位置),層級大的會覆寫在層級小的 Window 上面,這和 HTML 中的 z-index 概念是完全一緻的。在三種 Window 中,應用 Window 層級範圍是 1~99,子 Window 層級範圍是 1000~1999,系統 Window 層級範圍是 2000~2999,我們可以用一個表格來直覺的表示
Window 層級
應用 1-99
1000-1999
系統 2000-299
這些層級是對應的WindowManager.LayoutParams 的 type 參數,如下圖:
筆記27 | 通過WindowManager實作懸浮視窗總結 目錄
筆記27 | 通過WindowManager實作懸浮視窗總結 目錄

ViewManager和WindowManager的實作

  • ViewManager
我們對 Window 的操作是通過 WindowManager 來完成的,WindowManager繼承于 ViewManagerWindowManager 是一個接口,它繼承自隻有三個方法的 ViewManager 接口:
  1. public interface ViewManager
  2. {
  3.    /**
  4.     * 讓您添加和删除子視圖到活動的接口。得到一個執行個體
  5.     */
  6.    public void addView(View view, ViewGroup.LayoutParams params);
  7.    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
  8.    public void removeView(View view);
  9. }
三個方法其實就是 WindowManager 對外提供的主要功能,即添加 View、更新 View 和删除 View
  • WindowManager實作 
筆記27 | 通過WindowManager實作懸浮視窗總結 目錄
  1.    public void show(){
  2.        if (mContentView != null) {
  3.            wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
  4.            wmParams.format = PixelFormat.RGBA_8888;
  5.            wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
  6.            wmParams.alpha = 1.0F;
  7.            wmParams.gravity = Gravity.TOP | Gravity.LEFT;
  8.            wmParams.x = 0;
  9.            wmParams.y = 0;
  10.            wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
  11.            wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
  12.            wm.addView(mContentView, wmParams);
  13.            bShow=true;
  14.        }
  15.    }
  1. 權限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

舉例實作

  • service
  1. /*
  2. * ervice中随時監聽限制條件的變化以調動懸浮開關
  3. */
  4. private Timer mTimer = null;
  5.    private TimerTask mTimerTask = null;
  6.    private void upTime() {//開啟一個線程,在service中随時監聽限制條件的變化
  7.        this.mTimerTask=new TimerTask() {
  8.            @Override
  9.            public void run() {
  10.                handler.post(new Runnable() {
  11.                        @Override
  12.                        public void run() {
  13.                            if () {//限制條件
  14.                            MyWindowManager.createwinm(getApplicationContext());//開啟視窗
  15.                            }  
  16.                        }
  17.                    });
  18.                }else  
  19.                    if () { //限制條件
  20.                        MyWindowManager.removewinm(getApplicationContext());//關閉視窗
  21.                    }
  22.        };
  23.        this.mTimer.schedule(mTimerTask, 300, 300);
  24.    }
  • WindowManager
  1. /*
  2. * 定義一個實作WindowManager的類,所有需要懸浮的界面可以在此類中定義windowManager
  3. */
  4. public class MyWindowManager {
  5. public static CarDoor carDoor;
  6. public static LayoutParams doorParams;
  7. public static void createwinm(Context context) {
  8.        WindowManager windowManager = getWindowManager(context);
  9.        if (carDoor == null) {
  10.            carDoor = new CarDoor(context);
  11.            if (doorParams == null) {
  12.                doorParams = new LayoutParams();
  13.                doorParams.type = LayoutParams.TYPE_PHONE;
  14.                doorParams.format = PixelFormat.RGBA_8888;
  15.                doorParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
  16.                        | LayoutParams.FLAG_NOT_FOCUSABLE;
  17.                doorParams.gravity = Gravity.CENTER;
  18.                doorParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
  19.                doorParams.width = carDoor.viewWidth;
  20.                doorParams.height = carDoor.viewHight;
  21.                doorParams.x = 0;
  22.                doorParams.y = 0;
  23.            }
  24.            carDoor.setParams(doorParams);
  25.            windowManager.addView(carDoor, doorParams);
  26.            carDoor.updateViewPosition();
  27.        }
  28.    }
  29.    public static void removewinm(Context context) {
  30.        if (carDoor != null) {
  31.            carDoor.mTimerTask.cancel();
  32.            WindowManager windowManager = getWindowManager(context);
  33.            windowManager.removeView(carDoor);
  34.            carDoor = null;
  35.        }
  36.    }
  37. }
  • CarDoor
  1. /*
  2. * 懸浮界面要要實作什麼功能在此類定義就好了;
  3. */
  4. public class CarDoor extends LinearLayout {
  5. public CarDoor(Context context) {
  6.        super(context);
  7.        windowManager=(WindowManager) context.getSystemService(context.WINDOW_SERVICE);
  8.        LayoutInflater.from(context).inflate(R.layout.layout_cardoor,this);
  9.        View view=findViewById(R.id.layout_cardoor1);
  10.        viewWidth=view.getLayoutParams().width;
  11.        viewHight=view.getLayoutParams().height;
  12.        initView(view);
  13.        initData();
  14.        test1();
  15.    }
  16. }

筆記26 | 總結Android的擷取系統時間的幾種方法

筆記25 | 通過自定義VIEW實作一個圓盤轉動UI

筆記24 | 一個中間打開界面的動畫

筆記23 | 複習了/而/做......而的幾種循環用法

筆記22 |  學習整理開源APP(BaseAnimation)程式源碼“中的通訊錄效果(三)

結束

筆記27 | 通過WindowManager實作懸浮視窗總結 目錄

繼續閱讀