Android懸浮窗的實(shí)現(xiàn)步驟
最近想做一個(gè)懸浮窗秒表的功能,所以看下懸浮窗具體的實(shí)現(xiàn)步驟
1、初識(shí)WindowManager
實(shí)現(xiàn)懸浮窗主要用到的是WindowManager
@SystemService(Context.WINDOW_SERVICE) public interface WindowManager extends ViewManager { ... }
WindowManager是接口類(lèi),繼承自接口ViewManager,可以通過(guò)獲取WINDOW_SERVICE系統(tǒng)服務(wù)得到。而ViewManager接口有addView方法,我們就是通過(guò)這個(gè)方法將懸浮窗控件加入到屏幕中去。
2、設(shè)置權(quán)限
當(dāng)API Level >= 23,顯示懸浮窗功能,需要在清單文件AndroidManifest.xml中添加SYSTEM_ALERT_WINDOW權(quán)限,添加這個(gè)權(quán)限后才可以在其他應(yīng)用上顯示懸浮窗。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
通過(guò)getSystemService方式獲取WindowManager
val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
3、LayoutParam設(shè)置
WindowManager的addView方法有兩個(gè)參數(shù),一個(gè)是需要加入的控件對(duì)象,另一個(gè)參數(shù)是WindowManager.LayoutParams對(duì)象。
// view – The view to be added to this window. // params – The LayoutParams to assign to view. public void addView(View view, ViewGroup.LayoutParams params);
其中LayoutParams的type變量,這個(gè)變量是用來(lái)指定窗口的類(lèi)型。在設(shè)置這個(gè)變量時(shí),需要對(duì)不同版本的Android系統(tǒng)進(jìn)行適配。
val layoutParams = WindowManager.LayoutParams() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE }
在Android 8.0之前,懸浮窗口設(shè)置可以為T(mén)YPE_PHONE,這種類(lèi)型是用于提供用戶交互操作的非應(yīng)用窗口,現(xiàn)在這個(gè)類(lèi)型已棄用了。
而Android 8.0對(duì)系統(tǒng)和API行為做了修改,包括使用SYSTEM_ALERT_WINDOW權(quán)限的應(yīng)用無(wú)法再使用窗口類(lèi)型來(lái)在其他應(yīng)用和窗口上方顯示提醒窗口:
TYPE_PHONE(已棄用)
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR
如果需要實(shí)現(xiàn)在其他應(yīng)用和窗口上方顯示提醒窗口,那么必須該為T(mén)YPE_APPLICATION_OVERLAY的新類(lèi)型。
4、檢測(cè)是否允許開(kāi)啟懸浮窗
開(kāi)啟懸浮窗之前,還需要檢測(cè)用戶是否允許開(kāi)啟懸浮窗,通過(guò)系統(tǒng)提供的canDrawOverlays來(lái)檢測(cè)
//檢測(cè)是否允許開(kāi)啟懸浮窗 Settings.canDrawOverlays(context)
如果沒(méi)有允許開(kāi)啟,需要跳轉(zhuǎn)開(kāi)啟頁(yè)面,讓用戶允許開(kāi)啟懸浮窗
startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION))
5、FloatingService服務(wù)
懸浮窗一直顯示在其他應(yīng)用上層,需要新建FloatingService服務(wù)類(lèi),用于處理懸浮窗相關(guān)邏輯。
class FloatingService : Service() { override fun onCreate() { super.onCreate() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { showFloatingWindow(); return super.onStartCommand(intent, flags, startId) } override fun onBind(intent: Intent?): IBinder? { return null } /** * 顯示懸浮窗 */ private fun showFloatingWindow() { // 獲取WindowManager服務(wù) val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager // 新建懸浮窗控件 val button = Button(applicationContext) button.text = "Floating Window" button.setBackgroundColor(Color.BLUE) // 設(shè)置LayoutParam val layoutParams = WindowManager.LayoutParams() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE } layoutParams.format = PixelFormat.RGBA_8888 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE layoutParams.width = ActionBar.LayoutParams.WRAP_CONTENT layoutParams.height = ActionBar.LayoutParams.WRAP_CONTENT layoutParams.x = 300 layoutParams.y = 300 // 將懸浮窗控件添加到WindowManager windowManager.addView(button, layoutParams); } }
6、啟動(dòng)FloatingService
viewBinding.btnFloating.setOnClickListener { if (Settings.canDrawOverlays(this)) {//檢測(cè)是否具有懸浮窗權(quán)限 startService(Intent(this,FloatingService::class.java)) } else { startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)); } }
開(kāi)啟效果如下:
7、增加拖動(dòng)功能
懸浮窗顯示的位置可能會(huì)遮擋其他信息,這時(shí)就需要新增拖動(dòng)功能,可以拖動(dòng)到任何位置,實(shí)現(xiàn)的邏輯就是給布局View添加觸摸事件,根據(jù)觸摸和移動(dòng)的位置來(lái)決定懸浮窗顯示的位置。
var x = 0 var y = 0 button.setOnTouchListener { view, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { x = event.rawX.toInt() y = event.rawY.toInt() } MotionEvent.ACTION_MOVE -> { val nowX = event.rawX.toInt() val nowY = event.rawY.toInt() val movedX = nowX - x val movedY = nowY - y x = nowX y = nowY layoutParams.x = layoutParams.x + movedX layoutParams.y = layoutParams.y + movedY // 更新懸浮窗控件布局 windowManager.updateViewLayout(view, layoutParams) } else -> {} } false }
到此這篇關(guān)于Android懸浮窗的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Android懸浮窗內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 使用Android實(shí)現(xiàn)跨頁(yè)面懸浮窗效果
- Android開(kāi)發(fā)懸浮窗踩坑解決
- Android 無(wú)障礙全局懸浮窗實(shí)現(xiàn)示例
- Android實(shí)現(xiàn)懸浮窗效果
- Android應(yīng)用內(nèi)懸浮窗Activity的簡(jiǎn)單實(shí)現(xiàn)
- Android超簡(jiǎn)單懸浮窗使用教程
- Android實(shí)現(xiàn)懸浮窗的簡(jiǎn)單方法實(shí)例
- Android創(chuàng)建懸浮窗的完整步驟
- Android?懸浮窗開(kāi)發(fā)示例((動(dòng)態(tài)權(quán)限請(qǐng)求?|?前臺(tái)服務(wù)和通知?|?懸浮窗創(chuàng)建?)
相關(guān)文章
利用Android 防止系統(tǒng)字體變化、顯示大小變化影響
這篇文章主要介紹了利用Android 防止系統(tǒng)字體變化、顯示大小變化影響方法的相關(guān)資料,需要的朋友可以參考下面文章的具體內(nèi)容,希望對(duì)你有所幫助2021-10-10Android視頻播放器屏幕左側(cè)邊隨手指上下滑動(dòng)亮度調(diào)節(jié)功能的原理實(shí)現(xiàn)
這篇文章主要介紹了Android視頻播放器屏幕左側(cè)邊隨手指上下滑動(dòng)亮度調(diào)節(jié)功能的原理實(shí)現(xiàn),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02Android 斷點(diǎn)續(xù)傳原理以及實(shí)現(xiàn)
這篇文章主要介紹了Android 斷點(diǎn)續(xù)傳原理以及實(shí)現(xiàn)的相關(guān)資料,這里對(duì)斷點(diǎn)續(xù)傳原理進(jìn)行了詳細(xì)介紹,需要的朋友可以參考下2016-12-12詳解Android中的沉浸式狀態(tài)欄效果實(shí)例
本篇文章主要介紹了Android中的沉浸式狀態(tài)欄效果,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12使用Java代碼在Android中實(shí)現(xiàn)圖片裁剪功能
這篇文章主要介紹了使用Java代碼在Android中實(shí)現(xiàn)圖片裁剪功能,許多應(yīng)用都需要此類(lèi)從相冊(cè)中選取圖片然后編輯的功能,需要的朋友可以參考下2015-07-07Android開(kāi)發(fā)apk反編譯和二次打包教程
反編譯不是讓各位開(kāi)發(fā)者去對(duì)一個(gè)應(yīng)用破解搞重裝什么的,主要目的是為了促進(jìn)開(kāi)發(fā)者學(xué)習(xí),借鑒好的代碼,提升自我開(kāi)發(fā)水平。下面我們就來(lái)研究下如何進(jìn)行APK反編譯以及二次打包2016-04-04Android?OkHttp庫(kù)簡(jiǎn)單使用和封裝教程助你快速掌握網(wǎng)絡(luò)請(qǐng)求技能
OkHttp是一個(gè)高效的HTTP客戶端庫(kù),適用于Android和Java應(yīng)用程序。它支持HTTP/2和SPDY協(xié)議,提供了同步和異步請(qǐng)求API、請(qǐng)求和響應(yīng)攔截器、連接池和多路復(fù)用器、緩存支持、GZIP和DEFLATE壓縮等功能,可以大大提高網(wǎng)絡(luò)請(qǐng)求的性能和可擴(kuò)展性2023-04-04Android逆向之dex2oat的實(shí)現(xiàn)解析
虛擬機(jī)的發(fā)生展經(jīng)歷了從初期的dalvik,到中期的dalvik,以及后期的ART。但是市面上的APK文件早已已經(jīng)全球流行。為了能夠讓這些APK不加改動(dòng)的在所有虛擬機(jī)上面運(yùn)行,google采用了類(lèi)似適配器模式。即在讓虛擬運(yùn)行之前多一道工序。就是dexopt2021-10-10