Skip to content

FloatingVideoPlaying

xinbaicheng edited this page Apr 1, 2017 · 1 revision

悬浮窗播放

本文档简要介绍使用KSYMediaPlayer实现悬浮窗播放的功能的方法

1. 使用场景

退出播放页面(Activity)但并不退出播放,在观看视频的同时可浏览其他信息

2. 实现方法

因Player独立于UI页面,实现此功能须使用KSYMediaPlayer,而不能使用KSYTextureView

2.1 权限申请

需新加权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

特别提醒:小米手机需在 应用授权 中手动开启相应权限方可实现浮窗功能

2.2 封装KSYMediaPlayer

KSYMediaPlayer封装为一个单例

public class KSYFloatingPlayer {

    private KSYMediaPlayer  mKsyMediaPlayer;

    private static KSYFloatingPlayer _instance;

    private KSYFloatingPlayer() {}

    public static KSYFloatingPlayer getInstance() {
        if (_instance == null) {
            synchronized (KSYFloatingPlayer.class) {
                if (_instance == null)
                    _instance = new KSYFloatingPlayer();
            }
        }

        return _instance;
    }

    public void init(Context context) {
        if (mKsyMediaPlayer != null) {
            mKsyMediaPlayer.release();
            mKsyMediaPlayer = null;
        }

        mKsyMediaPlayer = new KSYMediaPlayer.Builder(context).build();
    }
    public KSYMediaPlayer getKSYMediaPlayer() {
        return mKsyMediaPlayer;
    }

    public void destroy() {
        if (mKsyMediaPlayer != null)
            mKsyMediaPlayer.release();

        mKsyMediaPlayer = null;
    }
}

2.3 悬浮窗功能实现

/**
 * Created by xbc on 2017/3/15.
 * 悬浮窗
 */

public class KSYFloatingWindowView extends RelativeLayout {

    private static final String TAG = "KSYFloatingWindowView";

    private static final int JUST_CLICK = 5;

    private WindowManager mWindowManager;
    private WindowManager.LayoutParams mLayoutParams;

    private TextureView mTextureView;
    private Surface mSurface;
    private ImageView mQuit;

    private Handler mHandler;

    private int statusBarHeight;

    private float xInScreen, yInScreen; //当前手指位置

    private float xDownInScreen, yDownInScreen; //手指按下位置

    private float xInView, yInView;  //手指相对于悬浮窗位置


    public KSYFloatingWindowView(Context context) {
        super(context);
        init(context);
    }

    public KSYFloatingWindowView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public KSYFloatingWindowView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater.from(context).inflate(R.layout.floating_window, this);

        mTextureView = (TextureView) findViewById(R.id.floating_window_player_view);
        mQuit = (ImageView) findViewById(R.id.floating_window_quit);

        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
        mQuit.setOnClickListener(mOnClickListener);
    }

    public void updateViewLayoutParams(WindowManager.LayoutParams params) {
        mLayoutParams = params;
    }

    public void setHandler(Handler handler) {
        mHandler = handler;
    }

    // 在此处重写 onTouchEvent 处理相应的事件
    // 必须返回 true 表示在此已处理相应事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                if (Math.abs(xDownInScreen - xInScreen) < JUST_CLICK && Math.abs(yDownInScreen - yInScreen) < JUST_CLICK) {
                    if (mHandler != null)
                        mHandler.obtainMessage(FloatingPlayingActivity.LEAVE_FLOATING_WINDOW_PLAYING).sendToTarget();
                }
                break;
            case MotionEvent.ACTION_DOWN:
                xInView = event.getX(); //相对于view的坐标
                yInView = event.getY();

                //getRaw()返回相对于屏幕左上角坐标
                xDownInScreen = event.getRawX();
                yDownInScreen = event.getRawY() - getStatusBarHeight();

                xInScreen = xDownInScreen;
                yInScreen = yDownInScreen;
                break;
            case MotionEvent.ACTION_MOVE:
                xInScreen = event.getRawX();
                yInScreen = event.getRawY() - getStatusBarHeight();
                updateViewPosition();
                break;
        }
        return true;
    }

    private void updateViewPosition() {
        mLayoutParams.x = (int) (xInScreen - xInView);
        mLayoutParams.y = (int) (yInScreen - yInView);
        mWindowManager.updateViewLayout(this, mLayoutParams);
    }

    private int getStatusBarHeight() {
        if (statusBarHeight == 0) {
            try {
                Class<?> c = Class.forName("com.android.internal.R$dimen");
                Object o = c.newInstance();
                Field field = c.getField("status_bar_height");
                int x = (Integer) field.get(o);
                statusBarHeight = getResources().getDimensionPixelSize(x);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return statusBarHeight;
    }

    private OnClickListener mOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View view) {
            if (mHandler != null)
                mHandler.obtainMessage(FloatingPlayingActivity.REMOVE_FLOATING_WINDOW).sendToTarget();
        }
    };

    private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
            if (mSurface == null)
                mSurface = new Surface(surfaceTexture);

            KSYFloatingPlayer.getInstance().getKSYMediaPlayer().setSurface(mSurface);
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
            if (mSurface != null) {
                mSurface.release();
                mSurface = null;
            }

            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

        }
    };
}

2.4 页面切换

关闭旧页面, 需调用如下代码

KSYFloatingPlayer.getInstance().getKSYMediaPlayer().setSurface(null);

开启新页面后, 需设置新的Surface, 播放器会继续渲染视频

KSYFloatingPlayer.getInstance().getKSYMediaPlayer().setSurface(newSurface);
Clone this wiki locally