Android中懸浮窗的實現
最近專案裡面有使用懸浮簽名功能,在github上找了幾個專案學了一下,自己並記錄一下。
因為目前 我只需要 懸浮 和 手寫 兩個功能所以我就簡單的實現了一下自己的程式碼:Github
這邊文章只記錄懸浮的實現
懸浮許可權:
需要新增許可權:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
許可權檢查:
private void checkSetting() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "當前無許可權,請授權", Toast.LENGTH_SHORT).show(); startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE); } else { show(); } } else { show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "授權失敗", Toast.LENGTH_SHORT).show(); } else { show(); } } } }
懸浮的實現:
需要獲取WindowManager,然後建立自己顯示的View,併為View設定LayoutParams,這個過程同其他的ViewGroup是一致的(都實現了ViewManager)
最後 使用 addView(View view, ViewGroup.LayoutParams params) 新增到視窗上
WindowManager windowManager; View showingView; private void create() { // 新建懸浮窗控制元件 showingView = suspension.createView(); WindowManager.LayoutParams layoutParams = suspension.getLayoutParams(); // 將懸浮窗控制元件新增到WindowManager getWindowManager().addView(showingView, layoutParams); }
這裡的view就是普通的View即可
ViewGroup.LayoutParams 需要注意的就比較多了,也是懸浮實現的重要類:
1.屬性的設定
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { //app 內有效 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION; } //整個 系統有效(慎用) //layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; //設定沒有焦點不能touch,這樣其他的介面才可以滑動和操作 //如果想獨佔觸控事件就關閉這句話 //layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; layoutParams.format = PixelFormat.RGBA_8888;
2.大小位置的設定
//獲取螢幕大小
Display display = getWindowManager().getDefaultDisplay();
Point outSize = new Point();
display.getSize(outSize);
int width = outSize.x;
int height = outSize.y;
//根據需要設定位置大小
layoutParams.width = width;
layoutParams.height = height / 2;
layoutParams.x = 0;
layoutParams.y = height / 2;
現在簡單的懸浮就可以實現了,至於 狀態改變(平移,變大小,變透明,動畫效果),我後面有用到我再來記錄!!!
加餐
從這個結構我們可以看出來所有屬性中的重點中的重點就是這這定義了>。<
他們分別對應屬性:type(視窗型別),flags(各種行為選項/標誌),softInputMode(任何軟輸入區域所需的操作模式),layoutInDisplayCutoutMode(如果存在,控制視窗的佈局方式DisplayCutout
)。
type - 在API級別1中新增
視窗的常規型別。視窗型別主要分為三類:
- 應用程式視窗(範圍從
FIRST_APPLICATION_WINDOW
到LAST_APPLICATION_WINDOW
)是普通的頂級應用程式視窗。對於這些型別的視窗,token
必須將設定為它們所屬的活動的令牌(如果token
為null,通常會為您完成)。 - 子視窗(從
FIRST_SUB_WINDOW
到LAST_SUB_WINDOW
)與另一個頂級視窗相關聯。對於這些型別的視窗,token
必須是其所連線的視窗的標記。 - 系統視窗(範圍從
FIRST_SYSTEM_WINDOW
到LAST_SYSTEM_WINDOW
)是供系統用於特定目的的特殊型別的視窗。應用程式通常不應使用它們,並且需要特殊許可才能使用它們。
常用值:
TYPE_ACCESSIBILITY_OVERLAY:僅被連線覆蓋的視窗,用於攔截使用者互動,而不會更改可訪問性服務可以自檢的視窗。特別是,可訪問性服務只能自檢可見使用者可以與之互動的視窗,他們可以觸控這些視窗或可以鍵入這些視窗。例如,如果有一個可觸控的全屏可訪問性覆蓋,則可訪問性服務將自檢其下方的視窗,即使它們被可觸控視窗覆蓋。
TYPE_APPLICATION:普通應用程式視窗。的token
必須是令牌識別視窗屬於誰的活動。在多使用者系統中,僅在擁有使用者的視窗上顯示。
TYPE_APPLICATION_ATTACHED_DIALOG:類似TYPE_APPLICATION_PANEL
,但是視窗的佈局與頂級視窗的佈局相同,而不是其容器的子級。
TYPE_APPLICATION_MEDIA:用於顯示媒體(例如視訊)的視窗。這些視窗顯示在其附加視窗的後面。
TYPE_APPLICATION_OVERLAY:應用程式覆蓋視窗顯示在所有活動視窗上方(介於FIRST_APPLICATION_WINDOW
和之間的型別LAST_APPLICATION_WINDOW
),但顯示在關鍵系統視窗(例如狀態列或IME)下方。系統可以隨時更改這些視窗的位置,大小或可見性,以減少使用者的視覺混亂並管理資源。需要android.Manifest.permission#SYSTEM_ALERT_WINDOW
許可。系統將使用這種視窗型別調整程序的重要性,以減少低記憶體殺手殺死程序的機會。在多使用者系統中,僅在擁有使用者的螢幕上顯示。
TYPE_PHONE(慎用):視窗型別:電話。這些是非應用程式視窗,提供使用者與電話的互動(尤其是來電)。這些視窗通常位於所有應用程式的上方,但位於狀態列的後面。在多使用者系統中,在所有使用者的視窗上顯示。
TYPE_SYSTEM_ALERT(慎用):視窗型別:系統視窗,例如低電量警報。這些視窗始終位於應用程式視窗的頂部。在多使用者系統中,僅在擁有使用者的視窗上顯示。
-------有狀態的
TYPE_STATUS_BAR:視窗型別:狀態列。只能有一個狀態列視窗。它位於螢幕頂部,所有其他視窗都向下移,使其位於螢幕下方。在多使用者系統中,在所有使用者的視窗上顯示。
TYPE_INPUT_METHOD:視窗型別:內部輸入法視窗,顯示在普通UI上方。可以調整應用程式視窗的大小或平移該視窗,以保持輸入焦點在顯示此視窗時可見。在多使用者系統中,僅在擁有使用者的視窗上顯示。
flags - Added inAPI level 1
Various behavioral options/flags. Default is none.
See Also
#FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
#FLAG_DIM_BEHIND
#FLAG_NOT_FOCUSABLE
#FLAG_NOT_TOUCHABLE
#FLAG_NOT_TOUCH_MODAL
#FLAG_TOUCHABLE_WHEN_WAKING
#FLAG_KEEP_SCREEN_ON
#FLAG_LAYOUT_IN_SCREEN
#FLAG_LAYOUT_NO_LIMITS
#FLAG_FULLSCREEN
#FLAG_FORCE_NOT_FULLSCREEN
#FLAG_SECURE
#FLAG_SCALED
#FLAG_IGNORE_CHEEK_PRESSES
#FLAG_LAYOUT_INSET_DECOR
#FLAG_ALT_FOCUSABLE_IM
#FLAG_WATCH_OUTSIDE_TOUCH
#FLAG_SHOW_WHEN_LOCKED
#FLAG_SHOW_WALLPAPER
#FLAG_TURN_SCREEN_ON
#FLAG_DISMISS_KEYGUARD
#FLAG_SPLIT_TOUCH
#FLAG_HARDWARE_ACCELERATED
#FLAG_LOCAL_FOCUS_MODE
#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
softInputMode - 在API級別3中新增
任何軟輸入區域所需的操作模式。可以是以下各項的任意組合:
- 其中的可見性狀態的
SOFT_INPUT_STATE_UNSPECIFIED
,SOFT_INPUT_STATE_UNCHANGED
,SOFT_INPUT_STATE_HIDDEN
,SOFT_INPUT_STATE_ALWAYS_HIDDEN
,SOFT_INPUT_STATE_VISIBLE
,或SOFT_INPUT_STATE_ALWAYS_VISIBLE
。 - 其中一個調節選項
SOFT_INPUT_ADJUST_UNSPECIFIED
,SOFT_INPUT_ADJUST_RESIZE
,SOFT_INPUT_ADJUST_PAN
,或SOFT_INPUT_ADJUST_NOTHING
。
可以通過android.R.attr#windowSoftInputMode
屬性在主題中控制此標誌。
layoutInDisplayCutoutMode - 在API級別28中新增
如果存在,控制視窗的佈局方式DisplayCutout
。
預設為LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
。
值可以是0
或的組合android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
,android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
,android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
,和android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS