可無縫切換小窗/全屏的android播放器實(shí)現(xiàn)

代碼:https://github.com/zackLangChina/AutoMonitorPlayer

效果:


普通模式多畫面 / 全屏播放
小窗模式

布局和拖拽功能介紹

普通窗口下的視圖層級關(guān)系??

將AutoMonitorPlayer作為控件時(shí),layout圖層關(guān)系如上圖。AutoMonitorPlayer內(nèi)部包含一個(gè)FrameLayout,將SurfaceView包含在內(nèi)。

頁面小窗

當(dāng)切換到小窗模式時(shí),AutoMonitorPlayer將容器Framelayout刪除出子節(jié)點(diǎn),外部的根節(jié)點(diǎn)android.R.id.content再將容器FrameLayout加為子節(jié)點(diǎn):

//父節(jié)點(diǎn)變了,需要從老的父節(jié)點(diǎn)處刪掉容器

this.removeView(mContainer);

//android.R.id.content是MainActivity布局最外面的一層FrameLayout

ViewGroup contentView?=(ViewGroup)NiceUtil.scanForActivity(mContext).findViewById(android.R.id.content);

FrameLayout.LayoutParams params?=mConfig.getTinyWindowLayoutParams();contentView.addView(mContainer,params);

關(guān)于小窗的拖拽,自定義繼承自FrameLayout的類(DragFrameLayout)作為SurfaceView容器類,接收到onTouch回調(diào)的移動消息后,調(diào)用layout修改自己的位置,接收到up消息后,調(diào)用setLayoutParams修改自身窗口參數(shù):

//臨時(shí)修改視圖顯示

layout(oriLeft,oriTop,oriRight,oriBottom);

//這里修改gravity,使用lefttopMargins的定位參數(shù),只需要給這兩個(gè)值就可以了((LayoutParams)oldParams).gravity = Gravity.LEFT | Gravity.TOP;((LayoutParams)oldParams).setMargins(oriLeft,oriTop,0,0);setLayoutParams(oldParams);

必須要說明的是,目前這種實(shí)現(xiàn)方式,小窗還是和頁面綁定的。如果要全局窗口,需要新建全局彈窗,再將FrameLayout作為該全局彈窗的視圖子節(jié)點(diǎn)。


全局小窗

全局窗口需要使用AlertDialog(TinyDialog):

getWindow().getAttributes().type = ?WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

使用AlertDialog要注意權(quán)限的申請,除了AndroidManifest.xml中申明權(quán)限,如果是android6.0以上的SDK,還需要在代碼中動態(tài)申請權(quán)限:

context.startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,????????Uri.parse("package:" + context.getPackageName())), 0);

創(chuàng)建了全局窗口,我們就要把FrameLayout容器放入這個(gè)窗口:

mTinyDialg.addContentView(mContainer,new FrameLayout.LayoutParams(????????ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

如圖,和頁面內(nèi)小窗比較類似,不同的是AlertDiaolg不再屬于應(yīng)用中的布局,即使切出應(yīng)用也可見。

關(guān)于全局小窗的拖拽。頁面小窗其實(shí)改變的是Framelayout的窗口位置,而全局小窗改變的是AlertDialog的窗口位置。

有一點(diǎn)很重要,我們知道Android有一套觸摸消息傳遞機(jī)制,默認(rèn)情況下會先傳遞給子布局,如果消息沒有被消費(fèi)掉,再一層層往上傳遞。AlertDialog作為FrameLayout的父節(jié)點(diǎn),要想優(yōu)先消費(fèi)觸摸消息,必須進(jìn)行消息攔截,要覆寫dispatchTouchEvent方法:

@Overridepublic boolean dispatchTouchEvent(@NonNull MotionEvent ev) {????return onTouchEvent(ev);}

然后根據(jù)觸摸坐標(biāo)確定要移動到哪里,再通過WindowManager改變自己的位置:

mWindowManager.updateViewLayout(getWindow().getDecorView(), layoutParams);


全屏

全屏?xí)r,同樣是AutoMonitorPlayer將容器Framelayout刪除出子節(jié)點(diǎn),外部的根節(jié)點(diǎn)android.R.id.content再將容器FrameLayout加為子節(jié)點(diǎn),同時(shí),需要隱藏ActionBar、狀態(tài)欄,并根據(jù)需要設(shè)置屏幕方向。


接口介紹

接口名參數(shù)說明

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容