Android仿優(yōu)酷視頻的懸浮窗播放效果
之前接了需求要讓視頻播放時可以像優(yōu)酷視頻那樣在懸浮窗里播放,并且懸浮窗和主播放頁面之間要實現(xiàn)無縫切換,項目中使用的是自封裝的ijkplayer
這個要求就代表不能在懸浮窗中新建視頻控件,所以需要在懸浮窗中復(fù)用主頁面的視頻控件,以達到無縫銜接的效果。
主頁面對應(yīng)的視頻控件的父view
<FrameLayout
android:id="@+id/vw_live"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
用FrameLayout作為添加視頻控件的ParentView,通過addview方法將新建的播放器控件添加到父控件內(nèi)部
vw_live = new IjkVideoView(this);
video_frame = findViewById(R.id.vw_live); video_frame.addView(vw_live);
主播放界面的啟動模式
播放主界面的activity的啟動模式不能為默認,因為我們要保證播放主界面在顯示懸浮窗的時候退到后臺,但是整個的應(yīng)用不能退到后臺,所以activity的啟動模式改為singleInstance
android:launchMode="singleInstance"
退到后臺我們通過moveTaskToBack(true)方法;
moveTaskToBack(true);
可以讓播放界面退到后臺而整個應(yīng)用不會退回后臺
權(quán)限請求
要使用懸浮窗需要申請權(quán)限
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "當前無權(quán)限,請授權(quán)", Toast.LENGTH_SHORT);
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);
}
懸浮窗
@SuppressLint("ClickableViewAccessibility")
public void showFloatingWindowView(IjkVideoView view) {
// 懸浮窗顯示視圖
LayoutInflater layoutInflater = LayoutInflater.from(activity);
mShowView = layoutInflater.inflate(R.layout.video_floating_window_layout, null);;
// 獲取系統(tǒng)窗口管理服務(wù)
mWindowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
// 懸浮窗口參數(shù)設(shè)置及返回
mFloatParams = getParams();
//floatingWindow內(nèi)部控件實例
init(view);
// 設(shè)置窗口觸摸移動事件
mShowView.setOnTouchListener(new FloatViewMoveListener());
// 懸浮窗生成
mWindowManager.addView(mShowView, mFloatParams);
}
private void init(IjkVideoView viewGroup){
videoLayout = mShowView.findViewById(R.id.floating_video);
videoLayout.removeAllViews();
if (viewGroup != null){
ijkVideoView = viewGroup;
videoLayout.addView(ijkVideoView,new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT
,ViewGroup.LayoutParams.MATCH_PARENT));
}
mBtnCloseFloatingWindow = mShowView.findViewById(R.id.close_floating_view);
mBtnCloseFloatingWindow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
mBtnBackFloatingWindow = (ImageView)mShowView.findViewById(R.id.back_floating_view);
mBtnBackFloatingWindow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
private WindowManager.LayoutParams getParams() {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
//設(shè)置懸浮窗口類型
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}
//設(shè)置懸浮窗口屬性
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
//設(shè)置懸浮窗口透明
layoutParams.format = PixelFormat.TRANSLUCENT;
//設(shè)置懸浮窗口長寬數(shù)據(jù)
layoutParams.width = 500;
layoutParams.height = 340;
//設(shè)置懸浮窗顯示位置
layoutParams.gravity = Gravity.START | Gravity.TOP;
layoutParams.x = 100;
layoutParams.y = 100;
return layoutParams;
}
懸浮窗的xml,可通過自定義獲得自己想要的效果
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/floating_video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/floating_video"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ImageView
android:id="@+id/close_floating_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="end"
android:padding="10dp"
android:src="@android:drawable/ic_menu_close_clear_cancel" />
<ImageView
android:id="@+id/back_floating_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="10dp"
android:src="@android:drawable/ic_menu_revert" />
</FrameLayout>
懸浮窗的滑動,我們可以通過自定義點擊監(jiān)聽實現(xiàn)
/**
* 浮窗移動/點擊監(jiān)聽
*/
private class FloatViewMoveListener implements View.OnTouchListener {
//開始觸控的坐標,移動時的坐標(相對于屏幕左上角的坐標)
private int mTouchStartX;
private int mTouchStartY;
//開始時的坐標和結(jié)束時的坐標(相對于自身控件的坐標)
private int mStartX, mStartY;
//判斷懸浮窗口是否移動,這里做個標記,防止移動后松手觸發(fā)了點擊事件
private boolean isMove;
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();
int x = (int) motionEvent.getX();
int y = (int) motionEvent.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
isMove = false;
mTouchStartX = (int) motionEvent.getRawX();
mTouchStartY = (int) motionEvent.getRawY();
mStartX = x;
mStartY = y;
break;
case MotionEvent.ACTION_MOVE:
int mTouchCurrentX = (int) motionEvent.getRawX();
int mTouchCurrentY = (int) motionEvent.getRawY();
mFloatParams.x += mTouchCurrentX - mTouchStartX;
mFloatParams.y += mTouchCurrentY - mTouchStartY;
mWindowManager.updateViewLayout(mShowView, mFloatParams);
mTouchStartX = mTouchCurrentX;
mTouchStartY = mTouchCurrentY;
float deltaX = x - mStartX;
float deltaY = y - mStartY;
if (Math.abs(deltaX) >= 5 || Math.abs(deltaY) >= 5) {
isMove = true;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
//如果是移動事件不觸發(fā)OnClick事件,防止移動的時候一放手形成點擊事件
return isMove;
}
}
懸浮窗的消失,在這里調(diào)用videoLayout.removeAllViews()是為了將復(fù)用的視頻控件的父View清空,返回主播放activity的時候調(diào)用addview方法不會再報 child view has Parent,you have to call removeView()的錯
public void dismiss() {
if (mWindowManager != null && mShowView != null) {
videoLayout.removeAllViews();
if (mShowView.getParent() != null){
mWindowManager.removeView(mShowView);
}
}
}
啟動懸浮窗
public videoFloatingWindow(Context context){
super(context);
this.activity = context;
}
對于懸浮窗的調(diào)用
用hasBind來記錄是否調(diào)用了懸浮窗
private void startFloatingWindow(){
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "當前無權(quán)限,請授權(quán)", Toast.LENGTH_SHORT);
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);
} else {
video_frame.removeView(vw_live);
videoFloatingWindow.getInstance(this).showFloatingWindowView(vw_live);
hasBind = true;
moveTaskToBack(true);
}
}
注意
一.由于主界面activity使用了singleInstance啟動模式,所以從懸浮窗返回主界面activity時,要添加flag
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
二.當主界面的activity退回后臺,再重新進入主界面的時候,注意,不再調(diào)用onCreate方法,而是調(diào)用onNewIntent,所以重寫onNewIntent方法,重新進入主界面,懸浮窗消失
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("RemoteView", "重新顯示了");
//不顯示懸浮框
if (hasBind){
videoFloatingWindow.getInstance(this).dismiss();
video_frame.removeAllViews();
if (vw_live != null){
video_frame.addView(vw_live);
}
hasBind = false;
}
}
總結(jié)
到此這篇關(guān)于Android仿優(yōu)酷視頻的懸浮窗播放的文章就介紹到這了,更多相關(guān)android 優(yōu)酷視頻懸浮窗播放內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java、android可用的rtp封包解包h264案例
- Android下拉刷新ListView——RTPullListView(demo)
- Android GSYVideoPlayer視頻播放器功能的實現(xiàn)
- Android實現(xiàn)本地Service方法控制音樂播放
- Android項目實現(xiàn)視頻播放器
- Android Studio實現(xiàn)音樂播放器
- Android Studio實現(xiàn)簡單音樂播放功能的示例代碼
- Android實現(xiàn)文字滾動播放效果的代碼
- Android10.0實現(xiàn)本地音樂播放(附源碼下載)
- Android原生視頻播放VideoView的使用
- Android手機通過rtp發(fā)送aac數(shù)據(jù)給vlc播放的實現(xiàn)步驟
相關(guān)文章
Android PopupWindow實現(xiàn)左側(cè)彈窗效果
這篇文章主要為大家詳細介紹了Android PopupWindow實現(xiàn)左側(cè)彈窗效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10
Android studio 使用Debugger問題(代碼中含有ndk)
這篇文章主要介紹了Android studio 使用Debugger問題(代碼中含有ndk),非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-11-11
Android apk 項目一鍵打包并上傳到蒲公英的實現(xiàn)方法
這篇文章主要介紹了Android apk 項目一鍵打包并上傳到蒲公英,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06
Android?性能優(yōu)化實現(xiàn)全量編譯提速的黑科技
這篇文章主要為大家介紹了Android?性能優(yōu)化實現(xiàn)全量編譯提速的黑科技,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
Android?Material組件庫日期選擇和時間選擇器的使用方法
這篇文章主要介紹了Android?Material組件庫(日期選擇和時間選擇器)基本使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11
Android通過應(yīng)用程序創(chuàng)建快捷方式的方法
這篇文章主要介紹了Android通過應(yīng)用程序創(chuàng)建快捷方式的方法,涉及Android基于應(yīng)用程序創(chuàng)建快捷方式的圖標及動作等技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09

