前言
一般的懸浮窗實(shí)現(xiàn)方式到逊,需要申請(qǐng)權(quán)限宙攻,并還是要對(duì)部分機(jī)型進(jìn)行適配才能正常顯示辕近。那么這里拔恰,我們換一種思路,實(shí)現(xiàn)一個(gè)不一樣的懸浮窗闹获。
一、應(yīng)用內(nèi)懸浮窗實(shí)現(xiàn)思路
通常的懸浮窗是通過WindowManager
直接添加的河哑,在不同的Android系統(tǒng)上需要做不同的適配避诽,在Android
6.0以上的機(jī)型上,還需要引導(dǎo)用戶跳轉(zhuǎn)到設(shè)置界面手動(dòng)開啟懸浮窗權(quán)限璃谨。雖然這樣實(shí)現(xiàn)懸浮窗有完整的解決方案沙庐,但是開啟懸浮窗過程對(duì)用戶并不是很友好。下面佳吞,我們換一種思路拱雏,去使用一個(gè)應(yīng)用內(nèi)懸浮窗,避免機(jī)型適配和權(quán)限申請(qǐng)的坑底扳,讓懸浮窗像普通的View
一樣顯示在界面上铸抑。
一般懸浮窗的實(shí)現(xiàn)方案是向系統(tǒng)window
添加type
為TYPE_PHONE
或者TYPE_TOAST
的View
,從而使懸浮窗可以作為一個(gè)獨(dú)立的View
進(jìn)行展示衷模。Android
對(duì)這一行為作了限制鹊汛,那我們可以考慮從比較常規(guī)的途徑添加View
:向每一個(gè)展示界面蒲赂,即Activity
,添加一個(gè)View
作為懸浮窗刁憋。這樣滥嘴,我們使用懸浮窗時(shí)就可以避免適配和權(quán)限問題。那么至耻,怎么樣實(shí)現(xiàn)這樣的懸浮窗更好呢若皱?
要實(shí)現(xiàn)這樣一個(gè)懸浮窗,相當(dāng)于我們要在Activity
加載完后將懸浮窗的View
添加的Activity
上尘颓,我們不想在原有的Activity上插入這段代碼走触,這時(shí)就可以利用ActivityLifecycleCallbacks
和fragment
的加載特性來完成一個(gè)無侵入式的懸浮窗的顯示。
二泥耀、應(yīng)用內(nèi)懸浮窗的實(shí)現(xiàn)
- 首先饺汹,我們先自定義一個(gè)
View
用于顯示懸浮窗界面,就叫它FloatingWindow
痰催。至于怎么實(shí)現(xiàn)兜辞,這個(gè)各位可以自由發(fā)揮。 - 接下來夸溶,我們要把
FloatingWindow
添加到每一個(gè)Activity
上逸吵,這時(shí)就利用ActivityLifecycleCallbacks
。Activity
的每個(gè)生命周期都能回調(diào)到ActivityLifecycleCallbacks
缝裁,這時(shí)我們只要在onActivityCreated(Activity activity, Bundle savedInstanceState)
中加上懸浮窗View
扫皱。但是,onActivityCreated(Activity activity, Bundle savedInstanceState)
方法是在onCreate(Bundle savedInstanceState)
時(shí)被調(diào)用的捷绑,我們需要保證在setContentView()
之后才添加懸浮窗韩脑,讓懸浮窗處于上層,所以我們插入一個(gè)空Fragment粹污,利用Fragment
的onActivityCreated(Bundle savedInstanceState)
是在Activity
的onCreate(Bundle savedInstanceState)
之后的特性來加入懸浮窗段多。
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
super.onActivityCreated(activity, savedInstanceState);
if (activity instanceof FragmentActivity) {
FragmentManager fm = ((FragmentActivity) activity).getSupportFragmentManager();
fm.beginTransaction().add(new SupportFragment(), FRAGMENT_TAG).commitAllowingStateLoss();
}
}
...
});
public static class SupportFragment extends Fragment {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Activity activity = getActivity();
if (activity != null) {
FloatingWindow fw = new FloatingWindow(activity);
activity.addContentView(fw, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
}
}
通過這幾行核心代碼,我們便完成了一個(gè)不需要權(quán)限申請(qǐng)的懸浮窗壮吩。細(xì)節(jié)一點(diǎn)的實(shí)現(xiàn)可以參考我的demo:https://github.com/windinwork/floatingwindowdemo
三进苍、總結(jié)
像我們這樣的懸浮窗,有優(yōu)點(diǎn)也有缺點(diǎn)鸭叙。優(yōu)點(diǎn)顯而易見觉啊,它不需要向系統(tǒng)申請(qǐng)?zhí)厥獾臋?quán)限即可正常顯示;缺點(diǎn)的話即是每一個(gè)Activity
都有一個(gè)懸浮窗沈贝,相互獨(dú)立存在杠人,當(dāng)然這個(gè)是可以優(yōu)化一下實(shí)現(xiàn)方式解決的,這里不細(xì)講,另一個(gè)缺點(diǎn)即是這樣的懸浮窗無法在應(yīng)用退到后臺(tái)的時(shí)候存在搜吧,當(dāng)然在在合適的應(yīng)用場(chǎng)景這也不是問題市俊。以上便是一個(gè)無侵入式無權(quán)限的懸浮窗實(shí)現(xiàn)方式,希望能為小伙伴提供不同的懸浮窗實(shí)現(xiàn)思路滤奈。