悬窗播放视频,让你聊天看视频两不误(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/King1425/article/details/59527229

当年的毕业设计拿出来记录一下,实现效果图如下:

这里写图片描述

视频播放用的是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" />

猜你喜欢

转载自blog.csdn.net/King1425/article/details/59527229