当年的毕业设计拿出来记录一下,实现效果图如下:
视频播放用的是vitamio框架。这里只讨论实现悬浮窗播放视频的思路
1.点击视频播放器中的悬窗按钮,开启悬窗播放模式。这里启动了一个后台server。
先进入Home桌面,然后启动MediaPlaybackService
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
Intent mIntent = new Intent("createUI");
mIntent.setClass(PlayActivity.this, MediaPlaybackService.class);
startService(mIntent);
然后我们来看MediaPlaybackService中做了什么
当action为createUI的时候创建UI窗口,当为removeUI的时候销毁窗口
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
String cmd = intent.getStringExtra("command");
if ("createUI".equals(action)) {
createView(this);
} else if ("removeUI".equals(action)) {
fView = null;
sFloatView = null;
}
}
return START_STICKY;
}
createView方法中实例化MyFloatView并传入一个ViewGroup,并调用showLayoutView。
我们在MyFloatView中做实现悬窗的逻辑用WindowManager。
public ViewGroup fView;
MyFloatView sFloatView;
private void createView(Context context) {
if (fView != null) {
return;
}
fView = (ViewGroup) View.inflate(context, R.layout.float_main, null);
sFloatView = new MyFloatView(fView);
sFloatView.showLayoutView();
}
所以我们接下来要做的就是在MyFloatView中使用WindowManager,显示出来传入MyFloatView的ViewGroup
WindowManager的方法很简单,基本用到的就三个addView,removeView,updateViewLayout。
ViewGroup为悬浮的界面 :R.layout.float_main
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="200dp"
>
<io.vov.vitamio.widget.VideoView
android:id="@+id/surfaceView"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
<include layout="@layout/app_video_float"/>
</FrameLayout>
在MyFloatView中实例化一个播放器,初始化播放器,初始化悬窗。
private VideoView videoView;
public MyFloatView(ViewGroup layoutView)
{
mlayoutView = layoutView;
context = mlayoutView.getContext();
mlayoutView.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View paramView, MotionEvent paramMotionEvent)
{
//mlayoutView.getParent().requestDisallowInterceptTouchEvent(true);
onTouchEvent(paramMotionEvent);
return false;
}
});
initialUI();
initWindow();
}
看initialUI();里面代码 主要是设置videoView
private void initialUI()
{
fLayout=(FrameLayout) mlayoutView.findViewById(R.id.fLayout);
videoView=(VideoView) mlayoutView.findViewById(R.id.surfaceView);
ImageView iv_fillImageView=(ImageView) mlayoutView.findViewById(R.id.iv_fill);
ImageView iv_close=(ImageView) mlayoutView.findViewById(R.id.iv_off);
iv_play=(ImageView) mlayoutView.findViewById(R.id.iv_play);
ImageView iv_small=(ImageView) mlayoutView.findViewById(R.id.iv_small);
seekBar=(SeekBar) mlayoutView.findViewById(R.id.seekBar);
int progress=MyApplicaton.getValueProgress();
String pathString=MyApplicaton.getPath();
videoView.setVideoURI(Uri.parse(pathString));
videoView.seekTo(progress);
videoView.start();
isPlay = true;
videoView.setOnCompletionListener(this);
videoView.setOnBufferingUpdateListener(this);
videoView.setOnErrorListener(this);
videoView.setOnInfoListener(this);
videoView.setOnPreparedListener(this);
IntentFilter filter = new IntentFilter(ACTION_DESTROY_MOVIE);
context.registerReceiver(sReceiver, filter);
iv_fillImageView.setOnClickListener(this);
iv_close.setOnClickListener(this);
iv_play.setOnClickListener(this);
iv_small.setOnClickListener(this);
setListener();
update = new upDateSeekBar();
new Thread(update).start();
endGesture();
}
然后是initWindow(); 注释很清楚
public void initWindow()
{
// 获取WindowManager
wm = (WindowManager) context.getApplicationContext().getSystemService(
"window");
//获取LayoutParams
wmParams = new WindowManager.LayoutParams();
//这里是关键 这个FIRST_SYSTEM_WINDOW的值就是2000。2003和2002的区别就在于2003类型的View比2002类型的还要top,能显示在系统下拉状态栏之上!
wmParams.type =2002; /*LayoutParams.TYPE_SYSTEM_ALERT | */ //LayoutParams.TYPE_SYSTEM_OVERLAY;
// 设置图片格式,效果为背景透明
wmParams.format = PixelFormat.TRANSPARENT;
/**
*这里的flags也很关键
*代码实际是wmParams.flags |= FLAG_NOT_FOCUSABLE;
*40的由来是wmParams的默认属性(32)+ FLAG_NOT_FOCUSABLE(8)
*/
wmParams.flags =40;// LayoutParams.FLAG_NOT_TOUCH_MODAL
// | LayoutParams.FLAG_NOT_FOCUSABLE;
//| LayoutParams.FLAG_LAYOUT_NO_LIMITS;
// 设置悬浮窗口长宽数据
wmParams.width = VIEW_WIDTH;
wmParams.height = VIEW_HEIGHT;
wmParams.gravity = Gravity.LEFT | Gravity.TOP; //gravity属性 简单地说,就是窗口如何停靠。当设置了 Gravity.LEFT 或 Gravity.RIGHT 之后,x值就表示到特定边的距离。
//通过WindowManager中的Display获取屏幕大小:
currentDisplay = wm.getDefaultDisplay();
WIDTH = currentDisplay.getWidth();
HEIGHT = currentDisplay.getHeight();
wmParams.x = 0;// 以屏幕左上角为原点,设置x、y初始值
wmParams.y = 0;
}
实例化之后调用showLayoutView,把ViewGroup加入WindowManager窗口中
public void showLayoutView()
{
wm.addView(mlayoutView, wmParams);
}
然后通过onTouchEvent实现滑动窗口:
public boolean onTouchEvent(MotionEvent event) {
x = event.getRawX();
y = event.getRawY()-25;
Log.i("currP", "currX"+x+"====currY"+y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchStartX = event.getX();
mTouchStartY = event.getY();
Log.e("ACTION_DOWN", "ACTION_DOWN"+mTouchStartY+"====ACTION_DOWN"+y);
fLayout.setVisibility(View.VISIBLE);
break;
case MotionEvent.ACTION_MOVE:
Log.e("ACTION_MOVE", "ACTION_MOVE"+mTouchStartY+"====ACTION_MOVE"+y);
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
updateViewPosition();
mTouchStartX=mTouchStartY=0;
endGesture();
break;
}
return true;
}
private void updateViewPosition()
{
wmParams.x = (int) (x - mTouchStartX);
wmParams.y = (int) (y - mTouchStartY);
wm.updateViewLayout(mlayoutView, wmParams);
}
5秒不触摸屏幕,去掉控制UI。
private void endGesture() {
disHandler.removeMessages(1);
disHandler.sendEmptyMessageDelayed(1, 5000);
}
private Handler disHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
fLayout.setVisibility(View.GONE);
}
}
};
关闭窗口的代码如下:
public void onExit()
{
//MyApplicaton.setValueProgress(valueProgress);
if(mlayoutView!=null){
try
{
wm.removeView(mlayoutView);
Intent mIntent = new Intent("removeUI");
mIntent.setClass(context, MediaPlaybackService.class);
context.startService(mIntent);
context.unregisterReceiver(sReceiver);
videoView.stopPlayback();
isPlay = false;
isFinish = true;
} catch (Exception e)
{
System.exit(0);
}
}
}
使用悬浮窗记得加权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />