实现思路
1、将Activity移动到后台
2、取出用于展示视频通话的View
3、开启服务,将视频通话的View显示在屏幕上
4、关闭服务,将视频通话的View重现添加进Activity
实现步骤
1、AndroidMainfest.xml中声明权限
//允许系统弹窗
2、设置中打开悬浮窗权限
(1)在打开悬浮窗前判断是否在设置中允许了悬浮窗权限
if (Build.VERSION.SDK_INT >=23 && !Settings.canDrawOverlays(getApplicationContext())) {
//启动Activity让用户授权
Intent intent =new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 10);
return;
}
//如果已有权限,正常打开悬浮窗
(2)在onActivityResult中判断是否打开了权限
3、开启悬浮窗
//最小化Activity
moveTaskToBack(true);
//保存视频View的引用
Constents.mVideoViewLayout =mLayoutManagerTrtc;
//开启服务显示悬浮框
Intent floatVideoIntent =new Intent(this, FloatVideoWindowService.class);
mServiceBound = bindService(floatVideoIntent, mVideoCallServiceConnection, Context.BIND_AUTO_CREATE);
4、FloatVideoWindowService 代码
/**
* 视频通话悬浮窗 服务
*/
public class FloatVideoWindowService extends Service {
public static final String TAG = FloatVideoWindowService.class.getSimpleName();
private WindowManager mWindowManager;
private WindowManager.LayoutParams wmParams;
private LayoutInflater inflater;
//浮动布局view
private View mFloatingLayout;
//返回的按钮
private View mCancelView;
//存放视频的父View
private FrameLayout mVideoView;
//触摸移动的view 触摸事件已被视频控件持有并使用。防止再次放到Activity时候出问题
private View mTouchView;
@Override
public void onCreate() {
super.onCreate();
initWindow();//设置悬浮窗基本参数(位置、宽高等)
}
@Nullable
@Override
public IBinderonBind(Intent intent) {
initFloating();//悬浮框点击事件的处理
return new MyBinder();
}
public class MyBinder extends Binder {
public FloatVideoWindowService getService() {
return FloatVideoWindowService.this;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
if (mFloatingLayout !=null) {
// 移除悬浮窗口
mWindowManager.removeView(mFloatingLayout);
mFloatingLayout =null;
Constents.isShowFloatWindow =false;
}
super.onDestroy();
}
/**
* 设置悬浮框基本参数(位置、宽高等)
*/
private void initWindow() {
mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//设置好悬浮窗的参数
wmParams = getParams();
// 悬浮窗默认显示以左上角为起始坐标
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
//悬浮窗的开始位置,因为设置的是从左上角开始,所以屏幕左上角是x=0;y=0
wmParams.x =70;
wmParams.y =210;
//得到容器,通过这个inflater来获得悬浮窗控件
inflater = LayoutInflater.from(getApplicationContext());
// 获取浮动窗口视图所在布局
mFloatingLayout =inflater.inflate(R.layout.alert_float_video_layout, null);
// 添加悬浮窗的视图
mWindowManager.addView(mFloatingLayout, wmParams);
}
private WindowManager.LayoutParams getParams() {
wmParams =new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
//设置可以显示在状态栏上
wmParams.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;
//设置悬浮窗口长宽数据
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
return wmParams;
}
private void initFloating() {
mCancelView =mFloatingLayout.findViewById(R.id.float_video_cancel);
mVideoView =mFloatingLayout.findViewById(R.id.float_video_content);
mTouchView =mFloatingLayout.findViewById(R.id.float_video_touch);
//腾讯视频布局管理者
TRTCVideoLayoutManager mTRTCVideoViewLayout = Constents.mVideoViewLayout;
if (mTRTCVideoViewLayout ==null) {
QLog.i(TAG, "没有找到VideoView");
return;
}
if (mTRTCVideoViewLayout.getParent() !=null) {
((ViewGroup) mTRTCVideoViewLayout.getParent()).removeView(mTRTCVideoViewLayout);
ViewGroup.LayoutParams layoutParams = mTRTCVideoViewLayout.getLayoutParams();
layoutParams.width = ScreenUtil.getPxByDp(80);
layoutParams.height = ScreenUtil.getPxByDp(120);
mVideoView.addView(mTRTCVideoViewLayout);
}
Constents.isShowFloatWindow =true;
//悬浮框点击事件
mCancelView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//在这里实现点击重新回到Activity
Intent intent =new Intent(FloatVideoWindowService.this, TRTCVideoCallActivity.class);
startActivity(intent);
}});
//悬浮框触摸事件,设置悬浮框可拖动
mTouchView.setOnTouchListener(new FloatingListener());
mTouchView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}});}
//开始触控的坐标,移动时的坐标(相对于屏幕左上角的坐标)
private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY;
//开始时的坐标和结束时的坐标(相对于自身控件的坐标)
private int mStartX, mStartY, mStopX, mStopY;
//判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件
private boolean isMove;
private class FloatingListener implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
isMove =false;
mTouchStartX = (int) event.getRawX();
mTouchStartY = (int) event.getRawY();
mStartX = (int) event.getX();
mStartY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
mTouchCurrentX = (int) event.getRawX();
mTouchCurrentY = (int) event.getRawY();
wmParams.x +=mTouchCurrentX -mTouchStartX;
wmParams.y +=mTouchCurrentY -mTouchStartY;
if (mWindowManager ==null ||mFloatingLayout ==null ||wmParams ==null) {
return false;
}
mWindowManager.updateViewLayout(mFloatingLayout, wmParams);
mTouchStartX =mTouchCurrentX;
mTouchStartY =mTouchCurrentY;
break;
case MotionEvent.ACTION_UP:
mStopX = (int) event.getX();
mStopY = (int) event.getY();
if (Math.abs(mStartX -mStopX) >=1 || Math.abs(mStartY -mStopY) >=1) {
isMove =true;
}
break;
default:
break;
}
//如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件
return isMove;
}}}
5、在Activity的onRestart()中,关闭服务。添加视频View
//不显示悬浮框
if (mServiceBound) {
unbindService(mVideoCallServiceConnection);
mServiceBound =false;
}
if (mLayoutManagerTrtc !=null &&mLayoutManagerTrtc.getParent() !=null) {
//先移除视频View的父布局,才能添加进Activity的根布局
((ViewGroup)mLayoutManagerTrtc.getParent()).removeView(mLayoutManagerTrtc);
//设置视频View的宽高
ViewGroup.LayoutParams layoutParams =mLayoutManagerTrtc.getLayoutParams();
layoutParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT;
layoutParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT;
//获取Activity的根布局
View childAt = ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);
//将视频View添加进Activity的根布局
((ConstraintLayout) childAt).addView(mLayoutManagerTrtc, 0);
}