Android悬浮窗播放视频

大家应该很喜欢这样的场景:一边打游戏一边看视频,生活娱乐两不误。这样应该怎么去实现呢?Android有提供悬浮窗API,使用悬浮窗播放视频,可以悬浮在其他应用上。有人可能会说,悬浮窗是不是会遮挡界面,导致用户体验不够好。总是有办法解决的,我们可以设计一个灵活的悬浮窗,窗口可以随时调整大小、任意拖动位置,这样就完美了。让我们看看小窗口播放效果。

首先,需要在Manifest.xml里申请权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>。对于高版本API,需要动态申请权限:

  private void requestAlertWindowPermission() {
      Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION");
      intent.setData(Uri.parse("package:" + getPackageName()));
      startActivityForResult(intent, 123);
  }

然后,创建一个FloatPlayerVView,添加到FloatWindow容器里。设置小窗口的x、y坐标位置,以及宽度、高度。开启小窗口后,视频会自动播放。差不多10多行代码:

private void floatingToPlay(){
    if (FloatWindow.get() != null) {
        return;
    }
    FloatPlayerView floatPlayerView = new FloatPlayerView(getApplicationContext());
    FloatWindow
            .with(getApplicationContext())
            .setView(floatPlayerView)
            .setWidth(Screen.width, 0.4f)
            .setHeight(Screen.width, 0.4f)
            .setX(Screen.width, 0.8f)
            .setY(Screen.height, 0.3f)
            .setMoveType(MoveType.slide)
            .setFilter(false)
            .setMoveStyle(500, new BounceInterpolator())
            .build();
    FloatWindow.get().show();
}

FloatPlayerView主要是创建一个VideoView播放器,添加到FrameLayout容器里,接着设置播放地址,开始播放。

private void init(Context context) {
    mPlayer = new VideoView(context);

    LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    layoutParams.gravity = Gravity.CENTER;
    addView(mPlayer, layoutParams);

    mPlayer.setVideoPath(VIDEO_PATH);
    mPlayer.requestFocus();
    mPlayer.start();
}

FloatWindow提供设置窗口大小、窗口位置、加载悬浮窗视图,加载过程是使用LayoutInflate实现:

static View inflate(Context applicationContext, int layoutId) {
    LayoutInflater inflate = (LayoutInflater) applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    return inflate.inflate(layoutId, null);
}

为了实现悬浮窗任意拖动,我们可以监听FloatWindow的TouchListener事件:

getView().setOnTouchListener(new View.OnTouchListener() {
    float lastX, lastY, changeX, changeY;
    int newX, newY;

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = event.getRawX();
                lastY = event.getRawY();
                cancelAnimator();
                break;
            case MotionEvent.ACTION_MOVE:
                changeX = event.getRawX() - lastX;
                changeY = event.getRawY() - lastY;
                newX = (int) (mFloatView.getX() + changeX);
                newY = (int) (mFloatView.getY() + changeY);
                mFloatView.updateXY(newX, newY);
                lastX = event.getRawX();
                lastY = event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                switch (mB.mMoveType) {
                    case MoveType.slide:
                        int startX = mFloatView.getX();
                        int endX = (startX * 2 + v.getWidth() >
                                Util.getScreenWidth(mB.mApplicationContext)) ?
                                Util.getScreenWidth(mB.mApplicationContext) - v.getWidth() : 0;
                        mAnimator = ObjectAnimator.ofInt(startX, endX);
                        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                int x = (int) animation.getAnimatedValue();
                                mFloatView.updateX(x);
                            }
                        });
                        startAnimator();
                        break;
                    case MoveType.back:
                        PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("x", mFloatView.getX(), mB.xOffset);
                        PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("y", mFloatView.getY(), mB.yOffset);
                        mAnimator = ObjectAnimator.ofPropertyValuesHolder(pvhX, pvhY);
                        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                int x = (int) animation.getAnimatedValue("x");
                                int y = (int) animation.getAnimatedValue("y");
                                mFloatView.updateXY(x, y);
                            }
                        });
                        startAnimator();
                        break;
                }
                break;

        }
        return false;
    }
});

为了保证小窗口能及时退出播放,不影响其他操作。我们可以设置LifeCycleListener监听器,比如监听到用户按下Home键、返回键等事件,就退出小窗口播放:

new FloatLifecycle(mB.mApplicationContext, mB.mShow, mB.mActivities, new LifecycleListener() {
    @Override
    public void onShow() {
        show();
    }

    @Override
    public void onHide() {
        hide();
    }

    @Override
    public void onPostHide() {
        postHide();
    }
});

至此,小窗口播放功能基本实现了,我们可以开启边玩游戏边看视频的愉快之旅。

发布了63 篇原创文章 · 获赞 179 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/u011686167/article/details/98122302