日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法

發(fā)布時(shí)間:2023/11/29 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.理清概念

我們使用過Dialog和PopupWindow,還有Toast,它們都顯示在Activity之上。那么我們首先需要理解的是android中是如何去繪制這些UI的呢?這里我只講我所理解的,首先看一層次圖(盜用網(wǎng)絡(luò)) 首先我們看到左邊的Activity層,我們使用到的Activity,其中會(huì)有一個(gè)PhoneWindow,這個(gè)每一個(gè)Activity都包含的,并且PhoneActivity去管理一個(gè)DecoView根視圖,并且這也解釋了我們使用的setContentView(int resId)就是將所有的UI組件放入到PhoneWindow中管理。我們也看到DecoView,加載后的資源都放入到這個(gè)View中。接下來會(huì)看到WindowManager,整個(gè)Android的窗口機(jī)制是基于一個(gè)叫做WindowManager,這個(gè)接口可以添加view到屏幕,也可以從屏幕刪除view。它面向的對(duì)象一端是屏幕,另一端就是View。而我們的android屏幕可以放多個(gè)窗口,除了Activity,我們還可以放Dialog,PopupWindow,我研究了一下PopupWIndow,就是通過WindowManager生產(chǎn)的。如果要自定義一個(gè)窗口,我們可以不用Dialog和PopupWindow,可以自己來實(shí)現(xiàn)它。 理解該圖,首先思考的是使用的Activity,會(huì)有一個(gè)PhoneWindow,這個(gè)用來管理View。而它的視圖是如何被繪制出來的呢,那是WindowManager的事情了,WindowManager就是添加和移除View,從屏幕上。

2.WindowManager介紹

WindowManager的方法很簡(jiǎn)單,有三個(gè)方法,AddView(),removeView(),updateViewLayout(); AddView();? ? //添加View removeView();? ??? ??? ? //移除VIew updateViewLayout()? ? //更新View 接下來看一個(gè)完整的代碼: View view = LayoutInflater.from(this).inflate(R.layout.dialog,null); //加載View視圖,這個(gè)就是我們要顯示的內(nèi)容 WindowManager windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); //獲取WindowManage WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); //設(shè)置LayoutParams的屬性 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; //該Type描述的是形成的窗口的層級(jí)關(guān)系,下面會(huì)詳細(xì)列出它的屬性 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | //該flags描述的是窗口的模式,是否可以觸摸,可以聚焦等 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; layoutParams.gravity = Gravity.CENTER; //設(shè)置窗口的位置 layoutParams.format = PixelFormat.TRANSLUCENT; //不設(shè)置這個(gè)彈出框的透明遮罩顯示為黑色 layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; //窗口的寬 layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; //窗口的高 layoutParams.token = ((View)findViewById(R.id.linearlayout)).getWindowToken(); //獲取當(dāng)前Activity中的View中的TOken,來依附Activity,因?yàn)樵O(shè)置了該值,納悶寫的這些代碼不能出現(xiàn)在onCreate();否則會(huì)報(bào)錯(cuò)。 windowManager.addView(view,layoutParams);

別忘了在AndroidManifest.xml中添加權(quán)限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

(1)那么接下啦介紹type值

layoutParams.type窗口類型。其中有三種主要類型: Applicationwindows:
取值在 FIRST_APPLICATION_WINDOW 和 LAST_APPLICATION_WINDOW 之間。
是通常的、頂層的應(yīng)用程序窗口。必須將 token 設(shè)置成 activity 的 token 。
Sub_windows:
取值在 FIRST_SUB_WINDOW 和 LAST_SUB_WINDOW 之間。
與頂層窗口相關(guān)聯(lián),token 必須設(shè)置為它所附著的宿主窗口的 token。
Systemwindows:
取值在 FIRST_SYSTEM_WINDOW 和 LAST_SYSTEM_WINDOW 之間。
用于特定的系統(tǒng)功能。它不能用于應(yīng)用程序,使用時(shí)需要特殊權(quán)限。 應(yīng)用程序窗口。
public static final int FIRST_APPLICATION_WINDOW = 1;?
所有程序窗口的“基地”窗口,其他應(yīng)用程序窗口都顯示在它上面。?
public static final int TYPE_BASE_APPLICATION =1; //-----------------------------------------------Applicationwindows ------------//
普通應(yīng)用功能程序窗口。token必須設(shè)置為Activity的token,以指出該窗口屬誰(shuí)。
public static final int TYPE_APPLICATION = 2;
用于應(yīng)用程序啟動(dòng)時(shí)所顯示的窗口。應(yīng)用本身不要使用這種類型。
它用于讓系統(tǒng)顯示些信息,直到應(yīng)用程序可以開啟自己的窗口。?
public static final int TYPE_APPLICATION_STARTING = 3;?
應(yīng)用程序窗口結(jié)束。
public static final int LAST_APPLICATION_WINDOW = 99; //-----------------------------------------------Applicationwindows ------------// //-----------------------------------------------Sub_windows------------// 子窗口。子窗口的Z序和坐標(biāo)空間都依賴于他們的宿主窗口。
public static final int FIRST_SUB_WINDOW = 1000; 面板窗口,顯示于宿主窗口上層??PopupWIndow就是使用的該模式。
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW; 媒體窗口,例如視頻。顯示于宿主窗口下層。
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1;
應(yīng)用程序窗口的子面板。顯示于所有面板窗口的上層。(GUI的一般規(guī)律,越“子”越靠上)
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW +2;
對(duì)話框。類似于面板窗口,繪制類似于頂層窗口,而不是宿主的子窗口。
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW +3;
媒體信息。顯示在媒體層和程序窗口之間,需要實(shí)現(xiàn)透明(半透明)效果。(例如顯示字幕)
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW +4;
子窗口結(jié)束。( End of types of sub-windows )
public static final int LAST_SUB_WINDOW = 1999; //-----------------------------------------------Sub_windows------------//

//-----------------------------------------------Systemwindows ?系統(tǒng)窗口------------// 系統(tǒng)窗口。非應(yīng)用程序創(chuàng)建。
public static final int FIRST_SYSTEM_WINDOW = 2000;
狀態(tài)欄。只能有一個(gè)狀態(tài)欄;它位于屏幕頂端,其他窗口都位于它下方。
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
搜索欄。只能有一個(gè)搜索欄;它位于屏幕上方。
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
電話窗口。它用于電話交互(特別是呼入)。它置于所有應(yīng)用程序之上,狀態(tài)欄之下。
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
系統(tǒng)提示。它總是出現(xiàn)在應(yīng)用程序窗口之上。
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW +3;
鎖屏窗口。
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW +4;
信息窗口。用于顯示toast。
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW +5;
系統(tǒng)頂層窗口。顯示在其他一切內(nèi)容之上。此窗口不能獲得輸入焦點(diǎn),否則影響鎖屏。
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW +6;
電話優(yōu)先,當(dāng)鎖屏?xí)r顯示。此窗口不能獲得輸入焦點(diǎn),否則影響鎖屏。
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW +7;
系統(tǒng)對(duì)話框。(例如音量調(diào)節(jié)框)。
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW +8;
鎖屏?xí)r顯示的對(duì)話框。
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW +9;
系統(tǒng)內(nèi)部錯(cuò)誤提示,顯示于所有內(nèi)容之上。
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW +10;
內(nèi)部輸入法窗口,顯示于普通UI之上。應(yīng)用程序可重新布局以免被此窗口覆蓋。
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW +11;
內(nèi)部輸入法對(duì)話框,顯示于當(dāng)前輸入法窗口之上。
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW +12;
墻紙窗口。
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW +13;
狀態(tài)欄的滑動(dòng)面板。
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW +14;
系統(tǒng)窗口結(jié)束。
public static final int LAST_SYSTEM_WINDOW = 2999;
//-----------------------------------------------Systemwindows------------//

?public int flags;

//------------------------------------flag-------------// 行為選項(xiàng)/旗標(biāo),默認(rèn)為 none .
下面定義了 flags 的取值:
窗口之后的內(nèi)容變暗。
public static final int FLAG_DIM_BEHIND = 0x00000002;

窗口之后的內(nèi)容變模糊。
public static final int FLAG_BLUR_BEHIND = 0x00000004;?

不許獲得焦點(diǎn)。
不能獲得按鍵輸入焦點(diǎn),所以不能向它發(fā)送按鍵或按鈕事件。那些時(shí)間將發(fā)送給它后面的可以獲得焦點(diǎn)的窗口。此選項(xiàng)還會(huì)設(shè)置FLAG_NOT_TOUCH_MODAL選項(xiàng)。設(shè)置此選項(xiàng),意味著窗口不能與軟輸入法進(jìn)行交互,所以它的Z序獨(dú)立于任何活動(dòng)的輸入法(換句話說,它可以全屏顯示,如果需要的話,可覆蓋輸入法窗口)。要修改這一行為,可參考FLAG_ALT_FOCUSALBE_IM選項(xiàng)。
public static final int FLAG_NOT_FOCUSABLE = 0x00000008;

不接受觸摸屏事件。
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;

當(dāng)窗口可以獲得焦點(diǎn)(沒有設(shè)置 FLAG_NOT_FOCUSALBE 選項(xiàng))時(shí),仍然將窗口范圍之外的點(diǎn)設(shè)備事件(鼠標(biāo)、觸摸屏)發(fā)送給后面的窗口處理。否則它將獨(dú)占所有的點(diǎn)設(shè)備事件,而不管它們是不是發(fā)生在窗口范圍內(nèi)。
public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;

如果設(shè)置了這個(gè)標(biāo)志,當(dāng)設(shè)備休眠時(shí),點(diǎn)擊觸摸屏,設(shè)備將收到這個(gè)第一觸摸事件。
通常第一觸摸事件被系統(tǒng)所消耗,用戶不會(huì)看到他們點(diǎn)擊屏幕有什么反應(yīng)。
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;

當(dāng)此窗口為用戶可見時(shí),保持設(shè)備常開,并保持亮度不變。
public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;

窗口占滿整個(gè)屏幕,忽略周圍的裝飾邊框(例如狀態(tài)欄)。此窗口需考慮到裝飾邊框的內(nèi)容。
public static final int FLAG_LAYOUT_IN_SCREEN =0x00000100;

允許窗口擴(kuò)展到屏幕之外。
public static final int FLAG_LAYOUT_NO_LIMITS =0x00000200;

窗口顯示時(shí),隱藏所有的屏幕裝飾(例如狀態(tài)條)。使窗口占用整個(gè)顯示區(qū)域。
public static final int FLAG_FULLSCREEN = 0x00000400;

此選項(xiàng)將覆蓋FLAG_FULLSCREEN選項(xiàng),并強(qiáng)制屏幕裝飾(如狀態(tài)條)彈出。
public static final int FLAG_FORCE_NOT_FULLSCREEN =0x00000800;

抖動(dòng)。指 對(duì)半透明的顯示方法。又稱“點(diǎn)透”。圖形處理較差的設(shè)備往往用“點(diǎn)透”替代Alpha混合。
public static final int FLAG_DITHER = 0x00001000;

不允許屏幕截圖。
public static final int FLAG_SECURE = 0x00002000;

一種特殊模式,布局參數(shù)用于指示顯示比例。
public static final int FLAG_SCALED = 0x00004000;

當(dāng)屏幕有可能貼著臉時(shí),這一選項(xiàng)可防止面頰對(duì)屏幕造成誤操作。
public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;

當(dāng)請(qǐng)求布局時(shí),你的窗口可能出現(xiàn)在狀態(tài)欄的上面或下面,從而造成遮擋。當(dāng)設(shè)置這一選項(xiàng)后,窗口管理器將確保窗口內(nèi)容不會(huì)被裝飾條(狀態(tài)欄)蓋住。
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;

反轉(zhuǎn)FLAG_NOT_FOCUSABLE選項(xiàng)。
如果同時(shí)設(shè)置了FLAG_NOT_FOCUSABLE選項(xiàng)和本選項(xiàng),窗口將能夠與輸入法交互,允許輸入法窗口覆蓋;
如果FLAG_NOT_FOCUSABLE沒有設(shè)置而設(shè)置了本選項(xiàng),窗口不能與輸入法交互,可以覆蓋輸入法窗口。
public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;

如果你設(shè)置了FLAG_NOT_TOUCH_MODAL,那么當(dāng)觸屏事件發(fā)生在窗口之外事,可以通過設(shè)置此標(biāo)志接收到一個(gè)MotionEvent.ACTION_OUTSIDE事件。注意,你不會(huì)收到完整的down/move/up事件,只有第一次down事件時(shí)可以收到ACTION_OUTSIDE。
public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;

當(dāng)屏幕鎖定時(shí),窗口可以被看到。這使得應(yīng)用程序窗口優(yōu)先于鎖屏界面。可配合FLAG_KEEP_SCREEN_ON選項(xiàng)點(diǎn)亮屏幕并直接顯示在鎖屏界面之前。可使用FLAG_DISMISS_KEYGUARD選項(xiàng)直接解除非加鎖的鎖屏狀態(tài)。此選項(xiàng)只用于最頂層的全屏幕窗口。
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;

請(qǐng)求系統(tǒng)墻紙顯示在你的窗口后面。窗口必須是半透明的。
public static final int FLAG_SHOW_WALLPAPER = 0x00100000;

窗口一旦顯示出來,系統(tǒng)將點(diǎn)亮屏幕,正如用戶喚醒設(shè)備那樣。
public static final int FLAG_TURN_SCREEN_ON = 0x00200000;

解除鎖屏。只有鎖屏界面不是加密的才能解鎖。如果鎖屏界面是加密的,那么用戶解鎖之后才能看到此窗口,除非設(shè)置了FLAG_SHOW_WHEN_LOCKED選項(xiàng)。
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;

鎖屏界面淡出時(shí),繼續(xù)運(yùn)行它的動(dòng)畫。
public static final int FLAG_KEEP_SURFACE_WHILE_ANIMATING =0x10000000;

以原始尺寸顯示窗口。用于在兼容模式下運(yùn)行程序。
public static final int FLAG_COMPATIBLE_WINDOW = 0x20000000;

用于系統(tǒng)對(duì)話框。設(shè)置此選項(xiàng)的窗口將無條件獲得焦點(diǎn)。
public static final int FLAG_SYSTEM_ERROR = 0x40000000;
//------------------------------------flag------------------------------------------------flag-------------//

public int softInputMode;

軟輸入法模式選項(xiàng):
以下選項(xiàng)與 softInputMode 有關(guān):
軟輸入?yún)^(qū)域是否可見。
public static final int SOFT_INPUT_MASK_STATE = 0x0f;

未指定狀態(tài)。
public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;

不要修改軟輸入法區(qū)域的狀態(tài)。
public static final int SOFT_INPUT_STATE_UNCHANGED = 1;

隱藏輸入法區(qū)域(當(dāng)用戶進(jìn)入窗口時(shí))。
public static final int SOFT_INPUT_STATE_HIDDEN = 2;

當(dāng)窗口獲得焦點(diǎn)時(shí),隱藏輸入法區(qū)域。
public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;

顯示輸入法區(qū)域(當(dāng)用戶進(jìn)入窗口時(shí))。
public static final int SOFT_INPUT_STATE_VISIBLE = 4;

當(dāng)窗口獲得焦點(diǎn)時(shí),顯示輸入法區(qū)域。
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;

窗口應(yīng)當(dāng)主動(dòng)調(diào)整,以適應(yīng)軟輸入窗口。
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;

未指定狀態(tài),系統(tǒng)將根據(jù)窗口內(nèi)容嘗試選擇一個(gè)輸入法樣式。
public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;

當(dāng)輸入法顯示時(shí),允許窗口重新計(jì)算尺寸,使內(nèi)容不被輸入法所覆蓋。
不可與SOFT_INPUT_ADJUSP_PAN混合使用,如果兩個(gè)都沒有設(shè)置,系統(tǒng)將根據(jù)窗口內(nèi)容自動(dòng)設(shè)置一個(gè)選項(xiàng)。
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;

輸入法顯示時(shí)平移窗口。它不需要處理尺寸變化,框架能夠移動(dòng)窗口以確保輸入焦點(diǎn)可見。
不可與SOFT_INPUT_ADJUST_RESIZE混合使用;如果兩個(gè)都沒設(shè)置,系統(tǒng)將根據(jù)窗口內(nèi)容自動(dòng)設(shè)置一個(gè)選項(xiàng)。
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;

當(dāng)用戶轉(zhuǎn)至此窗口時(shí),由系統(tǒng)自動(dòng)設(shè)置,所以你不要設(shè)置它。
當(dāng)窗口顯示之后該標(biāo)志自動(dòng)清除。
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;

public int gravity;

gravity 屬性。什么是gravity屬性呢?簡(jiǎn)單地說,就是窗口如何停靠。

9. public float horizontalMargin;
水平邊距,容器與widget之間的距離,占容器寬度的百分率。

10. public float verticalMargin;
縱向邊距。

11. public int format;
期望的位圖格式。默認(rèn)為不透明。參考android.graphics.PixelFormat。

12. public int windowAnimations;
窗口所使用的動(dòng)畫設(shè)置。它必須是一個(gè)系統(tǒng)資源而不是應(yīng)用程序資源,因?yàn)榇翱诠芾砥鞑荒茉L問應(yīng)用程序。

13. public float alpha = 1.0f;
整個(gè)窗口的半透明值,1.0表示不透明,0.0表示全透明。

14. public float dimAmount = 1.0f;
當(dāng)FLAG_DIM_BEHIND設(shè)置后生效。該變量指示后面的窗口變暗的程度。
1.0表示完全不透明,0.0表示沒有變暗。

15. public float screenBrightness = -1.0f;
用來覆蓋用戶設(shè)置的屏幕亮度。表示應(yīng)用用戶設(shè)置的屏幕亮度。
從0到1調(diào)整亮度從暗到最亮發(fā)生變化。

16.?public IBinder token = null;(改屬性標(biāo)識(shí)需要去依附的那個(gè)View,當(dāng)彈框不View進(jìn)行依附后,View被銷毀,如果沒有對(duì)彈框進(jìn)行銷毀,就會(huì)報(bào)錯(cuò)。)
窗口的標(biāo)示符。( Identifier for this window. This will usually be filled in for you. )

17. public String packageName = null;
此窗口所在的包名。

18. public int screenOrientation =ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
屏幕方向,參見android.content.pm.ActivityInfo#screenOrientation。 //------------------------------------------------------------------- 屬性大家估計(jì)是跳躍式看到,甚至都沒有看完,哈哈,本人也是沒有看完,但是掃了一下,知道大概。那么簡(jiǎn)單的說一下: layoutParams.type:窗口類型,它是用來定義窗口顯示在哪個(gè)地方,因?yàn)槠聊挥泻芏鄬?#xff0c;有很多視圖,具體顯示在哪里,就用type來定義了。比如顯示PopupWindow,就使用TYPE_APPLICATION_PANEL?,解釋:面板窗口,顯示于宿主窗口上層。它的值是在1000~1999。 在這個(gè)當(dāng)中的定義的值,都類似定義在視圖之上的子視圖。并且它一般在應(yīng)用中顯示。Systemwindows 類型的,是可以顯示在android機(jī)的桌面上的(并不需要依附應(yīng)用中的Activity). layoutParams.flags ?定義窗口的一些特性,比如說窗口是否聚焦,是否可以觸摸燈 其他的具體可以看上面的信息。
這是它的基本屬性的詳細(xì)描述,我們用到的就是上面我寫的代碼那幾個(gè)屬性。 屬性介紹完了,那么就來一個(gè)例子,顯示我們的成果。 首先定義一個(gè)視圖popwindow.xml文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:background="#66000000"> <RelativeLayout android:id="@+id/popupwindow" android:layout_width="200dp" android:layout_height="200dp" android:background="#ffffff"> <TextView android:id="@+id/title_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="標(biāo)題" android:textSize="22dp" android:textColor="#649DF2" android:layout_centerHorizontal="true" android:layout_marginTop="16dp"/> <View android:id="@+id/line" android:layout_width="match_parent" android:layout_height="1dp" android:background="#95BEF9" android:layout_below="@+id/title_tv" android:layout_marginTop="8dp"/> <TextView android:id="@+id/content_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="內(nèi)容" android:textSize="22dp" android:layout_centerHorizontal="true" android:layout_below="@+id/line" android:layout_marginTop="24dp"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@+id/content_tv" android:layout_marginTop="34dp" android:gravity="center"> <Button android:id="@+id/cancel_bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="取消"/> <Button android:id="@+id/ok_bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="確定" android:background="#649DF2"/> </LinearLayout> </RelativeLayout> </LinearLayout>

接下來去寫WIndowUtil

public class WindowUtils { private static View mView; private static Context mContext; private static WindowManager windowManager; public static Boolean isShown = false; public static void showPopupWindow(final Context context,int resId){ if (isShown){ return; } isShown = true; mContext = context.getApplicationContext(); windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mView = setUpView(mContext,resId); final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 如果設(shè)置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,彈出的View收不到Back鍵的事件 layoutParams.flags = flags; // 不設(shè)置這個(gè)彈出框的透明遮罩顯示為黑色 layoutParams.format = PixelFormat.TRANSLUCENT; // FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到后面的窗口 // 設(shè)置 FLAG_NOT_FOCUSABLE 懸浮窗口較小時(shí),后面的應(yīng)用圖標(biāo)由不可長(zhǎng)按變?yōu)榭砷L(zhǎng)按 // 不設(shè)置這個(gè)flag的話,home頁(yè)的劃屏?xí)袉栴} layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.gravity = Gravity.CENTER; windowManager.addView(mView,layoutParams); } /** * 隱藏彈框 */ public static void hidePopUpWindow(){ if (isShown && mView != null){ windowManager.removeViewImmediate(mView); isShown = false; } } private static View setUpView(Context context,int resId){ View view = LayoutInflater.from(context).inflate(resId,null); Button positiveBtn = (Button) view.findViewById(R.id.ok_bt); positiveBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //隱藏彈框 System.out.println("點(diǎn)擊了確定按鈕"); hidePopUpWindow(); } }); Button negativeBtn = (Button) view.findViewById(R.id.cancel_bt); negativeBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { System.out.println("點(diǎn)擊了取消按鈕"); hidePopUpWindow(); } }); final View popwindow = view.findViewById(R.id.popupwindow); //點(diǎn)擊彈框外面的,可以取消 view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); Rect rect = new Rect(); popwindow.getLocalVisibleRect(rect); if (!rect.contains(x,y)){ hidePopUpWindow(); } return false; } }); //點(diǎn)擊back鍵可消除 view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { switch (keyCode){ case KeyEvent.KEYCODE_BACK: hidePopUpWindow(); return true; default: return false; } } }); return view; } } 只需要在Activity調(diào)用 WindowUtils.showPopupWindow(WindowTest.this,R.layout.popupwindow);
權(quán)限不要忘了。

總結(jié):

理解了WindowManager后,再去理解Dialog和PopupWindow后,會(huì)容易很多,那PopupWindow來說,我們就當(dāng)它為一個(gè)窗口,使用了TYPE_APPLICATION_PANEL?模式的窗口,并且它依賴于當(dāng)前Activity,當(dāng)前Activity會(huì)傳入Token。這個(gè)窗口就和上面我們實(shí)現(xiàn)的例子很像了(PopupWindow內(nèi)部?jī)?nèi)部細(xì)節(jié)很多)。當(dāng)我們首先把它理解為一個(gè)窗口,然后在這個(gè)窗口中實(shí)現(xiàn)自己的操作,我們看源碼的時(shí)候,思路就會(huì)打開。

總結(jié)

以上是生活随笔為你收集整理的Android WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。