FloatingX ,一個強大的免權限懸浮窗組件,支持全域,以及區域懸浮窗,
背景
在前幾個月的業務開發中,我們 app 需要對懸浮窗進行更改,常見的懸浮窗實作方式分為兩種:
- 前者是獲取權限后,利用
WindowManager實作 - 后者是基于
DecorView實作的插入懸浮窗
選用怎樣的方案,主要根據業務的定向, 因為我們的業務不是視頻通話類,而是菜譜工具類,所以我們不愿意讓用戶為此去設定中授予權限,這是一件成本較大的事,故采用了后者的方案,業內知乎也使用的這種方案,
在之前的版本中,我們已經采用了后者的方案,先前的同學使用了插入到 content 中實作,但沒有經過太多封裝,代碼直接插入到了 base 層,對于當下而言,基本符合使用,但擴展成本太高,對于未來而言,這顯然不滿足要求,
于是我希望有這樣一個組件,它必須具備以下基本要求:
- 無感插入
- 可拖動
- 良好的分層設計
這是最開始的功能,但隨著封裝程序,以及對比知乎等其他懸浮窗,我發現可能可以讓這個東西更有意思,而不只是一個工具類,
經過了十幾個版本的優化與測驗,終于,FloatingX 迎來了第一個rc版本,api已相對固定👏,目前已在線上運行3個月+(beta開始),已通過測驗市場常見近百款機型,
Github: https://github.com/Petterpx/FloatingX,
特性
FloatingX 具備以下功能:
- 單例持有浮窗view
- 支持各項回呼監聽
- 鏈式呼叫,無感插入
- 支持自定義是否保存歷史位置及還原
- 支持插入
ViewGroup,Fragment,Activity - 允許自定義懸浮窗各項指標,自定義隱藏顯示影片
- 支持 越界回彈,多指觸摸,小屏適配,螢屏旋轉
- 支持自定義位置方向,自帶輔助定位顯示坐標
- 完善kotlin構建擴展,及對Java的友好兼容
- 支持顯示位置[強行修復],應對特殊機型(需要單獨開啟)
- 完善的日志系統,打開即可看到不同級別的Fx運行程序,更利于發現問題
- …
效果圖
| 全屏,activity,fragment,單view | 小屏展示 | 非正常比例縮放螢屏 |
|---|---|---|
![]() | ![]() | ![]() |
| 螢屏旋轉 | 功能演示 | |
|---|---|---|
![]() | ![]() |
如何使用
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.Petterpx:FloatingX:1.0-rc01'
}
完善的日志-查看器
開啟日志查看器,將看到Fx整個運行軌跡,更便于發現問題以及追蹤解決,同時支持自定義日志tag
| App | Activity | ViewGroup |
|---|---|---|
![]() | ![]() | ![]() |
全域懸浮窗管理
kt
FloatingX.init {
setContext(this@CustomApplication)
setLayout(R.layout.item_floating_new)
addBlackClass(
MainActivity::class.java,
NewActivity::class.java,
ImmersedActivity::class.java
)
//只有呼叫了show,才會監聽app-lifecycle,后續會自動插入activity中
show()
}
Java
AppHelper helper = AppHelper.builder()
.setContext(application)
.setLayout(R.layout.item_floating)
.build();
FloatingX.init(helper);
區域懸浮窗管理
通用創建方式
kt
ScopeHelper.builder {
setLayout(R.layout.item_floating)
}.toControl(activity)
kt && java
ScopeHelper.builder()
.setLayout(R.layout.item_floating)
.build()
.toControl(activity)
.toControl(fragment)
.toControl(viewgroup)
對kt的擴展支持
activity創建懸浮窗
private val activityFx by activityToFx(activity) {
setLayout(R.layout.item_floating)
}
fragment創建懸浮窗
private val fragment by fragmentToFx(fragment) {
setLayout(R.layout.item_floating)
}
viewGroup創建懸浮窗
private val viewFx by createFx({
init(viewGroup)
}) {
setLayout(R.layout.item_floating)
setEnableLog(true, "main_fx")
}
快速創建任意作用域懸浮窗
private val customCreateFx by createFx {
setLayout(R.layout.item_floating)
build().toControl(activity)
build().toControl(fragment)
build().toControl(viewgroup)
}
技術實作
App 級別懸浮窗 基于
DecorView的的實作方案,全域持有一個單獨的懸浮窗View,通過AppLifecycle監聽Activity生命周期,并在相應時機 插入到DecorView上 ;View 級別懸浮窗,基于給定的
ViewGroup;Fragment 級別,基于其對應的
rootView;Acrtivity 級別,基于
DecorView內部的R.id.content;
具體如下:
具體見我的博客:原始碼分析 | Activity-setContentView
Ps: 為什么App級別懸浮窗 要插入到 DecorView ,而不是 R.id.content -> FrameLayout ?
插入到
DecorView可以最大程度控制懸浮窗的自由度,即懸浮窗可以真正意義上[全屏]拖動,插入到
content中,其拖動范圍其實為 應用視圖范圍 ,即擺放位置 受到 狀態欄 和 底部導航欄 以及 默認的AppBar影響, 比如當用戶隱藏了狀態欄或者導航欄,相對應的視圖大小會發生改變,將影響懸浮窗的位置擺放,
感謝
基礎 懸浮窗View 源自 EnFloatingView 的 FloatingMagnetView 實作方式,并在其基礎上增加了一些改進,
對于導航欄的測量部分代碼來自,wenlu@掘金 ,并在其之上增加了更多適配,已覆寫市場大部分機型,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/293385.html
標籤:其他








