Переглянути джерело

完善视频悬浮播放自定义视图

杨充 4 роки тому
батько
коміт
1bda62992b

+ 61 - 0
VideoPlayer/src/main/java/org/yczbj/ycvideoplayerlib/ui/pip/CustomFloatController.java

@@ -0,0 +1,61 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.ui.pip;
+import android.content.Context;
+import android.util.AttributeSet;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import org.yczbj.ycvideoplayerlib.controller.GestureVideoController;
+import org.yczbj.ycvideoplayerlib.ui.view.CustomCompleteView;
+import org.yczbj.ycvideoplayerlib.ui.view.CustomErrorView;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/9
+ *     desc  : 悬浮播放控制器
+ *     revise:
+ * </pre>
+ */
+public class CustomFloatController extends GestureVideoController {
+
+    public CustomFloatController(@NonNull Context context) {
+        super(context);
+    }
+
+    public CustomFloatController(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected int getLayoutId() {
+        return 0;
+    }
+
+    @Override
+    protected void initView(Context context) {
+        super.initView(context);
+        addControlComponent(new CustomCompleteView(getContext()));
+        addControlComponent(new CustomErrorView(getContext()));
+        addControlComponent(new CustomFloatView(getContext()));
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}

+ 193 - 0
VideoPlayer/src/main/java/org/yczbj/ycvideoplayerlib/ui/pip/CustomFloatView.java

@@ -0,0 +1,193 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.ui.pip;
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.animation.Animation;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import org.yczbj.ycvideoplayerlib.R;
+import org.yczbj.ycvideoplayerlib.config.ConstantKeys;
+import org.yczbj.ycvideoplayerlib.controller.ControlWrapper;
+import org.yczbj.ycvideoplayerlib.controller.IControlComponent;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/9
+ *     desc  : 悬浮窗视图
+ *     revise:
+ * </pre>
+ */
+public class CustomFloatView extends FrameLayout implements IControlComponent, View.OnClickListener {
+
+    private ControlWrapper mControlWrapper;
+    private Context mContext;
+    private ImageView mIvStartPlay;
+    private ProgressBar mPbLoading;
+    private ImageView mIvClose;
+    private ImageView mIvSkip;
+
+    public CustomFloatView(@NonNull Context context) {
+        super(context);
+        init(context);
+    }
+
+    public CustomFloatView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public CustomFloatView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+    private void init(Context context){
+        this.mContext = context;
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.custom_video_player_float, this, true);
+        initFindViewById(view);
+        initListener();
+    }
+
+    private void initFindViewById(View view) {
+        mIvStartPlay = view.findViewById(R.id.iv_start_play);
+        mPbLoading = view.findViewById(R.id.pb_loading);
+        mIvClose = view.findViewById(R.id.iv_close);
+        mIvSkip = view.findViewById(R.id.iv_skip);
+
+    }
+
+    private void initListener() {
+        mIvStartPlay.setOnClickListener(this);
+        mIvClose.setOnClickListener(this);
+        mIvSkip.setOnClickListener(this);
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        if (v == mIvClose) {
+            FloatVideoManager.getInstance(mContext).stopFloatWindow();
+            FloatVideoManager.getInstance(mContext).reset();
+        } else if (v == mIvStartPlay) {
+            mControlWrapper.togglePlay();
+        } else if (v == mIvSkip) {
+            if (FloatVideoManager.getInstance(mContext).getActClass() != null) {
+                Intent intent = new Intent(getContext(), FloatVideoManager.getInstance(mContext).getActClass());
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                getContext().startActivity(intent);
+            }
+        }
+    }
+
+    @Override
+    public void attach(@NonNull ControlWrapper controlWrapper) {
+        mControlWrapper = controlWrapper;
+    }
+
+    @Override
+    public View getView() {
+        return this;
+    }
+
+    @Override
+    public void onVisibilityChanged(boolean isVisible, Animation anim) {
+        if (isVisible) {
+            if (mIvStartPlay.getVisibility() == VISIBLE){
+                return;
+            }
+            mIvStartPlay.setVisibility(VISIBLE);
+            mIvStartPlay.startAnimation(anim);
+        } else {
+            if (mIvStartPlay.getVisibility() == GONE){
+                return;
+            }
+            mIvStartPlay.setVisibility(GONE);
+            mIvStartPlay.startAnimation(anim);
+        }
+    }
+
+    @Override
+    public void onPlayStateChanged(int playState) {
+        switch (playState) {
+            case ConstantKeys.CurrentState.STATE_IDLE:
+                mIvStartPlay.setSelected(false);
+                mIvStartPlay.setVisibility(VISIBLE);
+                mPbLoading.setVisibility(GONE);
+                break;
+            case ConstantKeys.CurrentState.STATE_PLAYING:
+                mIvStartPlay.setSelected(true);
+                mIvStartPlay.setVisibility(GONE);
+                mPbLoading.setVisibility(GONE);
+                break;
+            case ConstantKeys.CurrentState.STATE_PAUSED:
+                mIvStartPlay.setSelected(false);
+                mIvStartPlay.setVisibility(VISIBLE);
+                mPbLoading.setVisibility(GONE);
+                break;
+            case ConstantKeys.CurrentState.STATE_PREPARING:
+                mIvStartPlay.setVisibility(GONE);
+                mIvStartPlay.setVisibility(VISIBLE);
+                break;
+            case ConstantKeys.CurrentState.STATE_PREPARED:
+                mIvStartPlay.setVisibility(GONE);
+                mPbLoading.setVisibility(GONE);
+                break;
+            case ConstantKeys.CurrentState.STATE_ERROR:
+                mPbLoading.setVisibility(GONE);
+                mIvStartPlay.setVisibility(GONE);
+                bringToFront();
+                break;
+            case ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED:
+                mIvStartPlay.setVisibility(GONE);
+                mPbLoading.setVisibility(VISIBLE);
+                break;
+            case ConstantKeys.CurrentState.STATE_COMPLETED:
+                mIvStartPlay.setVisibility(GONE);
+                mPbLoading.setVisibility(GONE);
+                mIvStartPlay.setSelected(mControlWrapper.isPlaying());
+                break;
+            case ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING:
+                bringToFront();
+                break;
+        }
+    }
+
+    @Override
+    public void onPlayerStateChanged(int playerState) {
+
+    }
+
+    @Override
+    public void setProgress(int duration, int position) {
+
+    }
+
+    @Override
+    public void onLockStateChanged(boolean isLocked) {
+
+    }
+
+}

+ 146 - 0
VideoPlayer/src/main/java/org/yczbj/ycvideoplayerlib/ui/pip/FloatVideoManager.java

@@ -0,0 +1,146 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.ui.pip;
+
+import android.content.Context;
+import android.view.View;
+import org.yczbj.ycvideoplayerlib.player.VideoPlayer;
+import org.yczbj.ycvideoplayerlib.player.VideoViewManager;
+import org.yczbj.ycvideoplayerlib.tool.PlayerUtils;
+
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/9
+ *     desc  : 悬浮播放
+ *     revise:
+ * </pre>
+ */
+public class FloatVideoManager {
+
+    //画中画
+    public static final String PIP = "pip";
+    private static FloatVideoManager instance;
+    private VideoPlayer mVideoPlayer;
+    private FloatVideoView mFloatView;
+    private CustomFloatController mFloatController;
+    private boolean mIsShowing;
+    private int mPlayingPosition = -1;
+    private Class mActClass;
+
+
+    private FloatVideoManager(Context context) {
+        mVideoPlayer = new VideoPlayer(context);
+        VideoViewManager.instance().add(mVideoPlayer, PIP);
+        mFloatController = new CustomFloatController(context);
+        mFloatView = new FloatVideoView(context, 0, 0);
+    }
+
+    public static FloatVideoManager getInstance(Context context) {
+        if (instance == null) {
+            synchronized (FloatVideoManager.class) {
+                if (instance == null) {
+                    instance = new FloatVideoManager(context);
+                }
+            }
+        }
+        return instance;
+    }
+
+    public void startFloatWindow() {
+        if (mIsShowing) {
+            return;
+        }
+        PlayerUtils.removeViewFormParent(mVideoPlayer);
+        mVideoPlayer.setVideoController(mFloatController);
+        mFloatController.setPlayState(mVideoPlayer.getCurrentPlayState());
+        mFloatController.setPlayerState(mVideoPlayer.getCurrentPlayerState());
+        mFloatView.addView(mVideoPlayer);
+        mFloatView.addToWindow();
+        mIsShowing = true;
+    }
+
+    public void stopFloatWindow() {
+        if (!mIsShowing) {
+            return;
+        }
+        mFloatView.removeFromWindow();
+        PlayerUtils.removeViewFormParent(mVideoPlayer);
+        mIsShowing = false;
+    }
+
+    public void setPlayingPosition(int position) {
+        this.mPlayingPosition = position;
+    }
+
+    public int getPlayingPosition() {
+        return mPlayingPosition;
+    }
+
+    public void pause() {
+        if (mIsShowing) {
+            return;
+        }
+        mVideoPlayer.pause();
+    }
+
+    public void resume() {
+        if (mIsShowing) {
+            return;
+        }
+        mVideoPlayer.resume();
+    }
+
+    public void reset() {
+        if (mIsShowing){
+            return;
+        }
+        PlayerUtils.removeViewFormParent(mVideoPlayer);
+        mVideoPlayer.release();
+        mVideoPlayer.setVideoController(null);
+        mPlayingPosition = -1;
+        mActClass = null;
+    }
+
+    public boolean onBackPress() {
+        return !mIsShowing && mVideoPlayer.onBackPressed();
+    }
+
+    public boolean isStartFloatWindow() {
+        return mIsShowing;
+    }
+
+    /**
+     * 显示悬浮窗
+     */
+    public void setFloatViewVisible() {
+        if (mIsShowing) {
+            mVideoPlayer.resume();
+            mFloatView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    public void setActClass(Class cls) {
+        this.mActClass = cls;
+    }
+
+    public Class getActClass() {
+        return mActClass;
+    }
+
+}

+ 173 - 0
VideoPlayer/src/main/java/org/yczbj/ycvideoplayerlib/ui/pip/FloatVideoView.java

@@ -0,0 +1,173 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.ui.pip;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Build;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import org.yczbj.ycvideoplayerlib.R;
+import org.yczbj.ycvideoplayerlib.tool.PlayerUtils;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/9
+ *     desc  : 悬浮窗控件(解决滑动冲突)
+ *     revise:
+ * </pre>
+ */
+@SuppressLint("ViewConstructor")
+public class FloatVideoView extends FrameLayout{
+
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mParams;
+
+    private int mDownRawX, mDownRawY;//手指按下时相对于屏幕的坐标
+    private int mDownX, mDownY;//手指按下时相对于悬浮窗的坐标
+
+    public FloatVideoView(@NonNull Context context, int x, int y) {
+        super(context);
+        mDownX = x;
+        mDownY = y;
+        init();
+    }
+
+
+    private void init() {
+        setBackgroundResource(R.drawable.shape_float_window_bg);
+        int padding = PlayerUtils.dp2px(getContext(), 1);
+        setPadding(padding, padding, padding, padding);
+        initWindow();
+    }
+
+    private void initWindow() {
+        mWindowManager = PlayerUtils.getWindowManager(getContext().getApplicationContext());
+        mParams = new WindowManager.LayoutParams();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
+            mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        }else {
+            mParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+        }
+        // 设置图片格式,效果为背景透明
+        mParams.format = PixelFormat.TRANSLUCENT;
+        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mParams.windowAnimations = R.style.FloatWindowAnimation;
+        mParams.gravity = Gravity.START | Gravity.TOP; // 调整悬浮窗口至右下角
+        // 设置悬浮窗口长宽数据
+        int width = PlayerUtils.dp2px(getContext(), 250);
+        mParams.width = width;
+        mParams.height = width * 9 / 16;
+        mParams.x = mDownX;
+        mParams.y = mDownY;
+    }
+
+    /**
+     * 添加至窗口
+     */
+    public boolean addToWindow() {
+        if (mWindowManager != null) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                if (!isAttachedToWindow()) {
+                    mWindowManager.addView(this, mParams);
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                try {
+                    if (getParent() == null) {
+                        mWindowManager.addView(this, mParams);
+                    }
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * 从窗口移除
+     */
+    public boolean removeFromWindow() {
+        if (mWindowManager != null) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                if (isAttachedToWindow()) {
+                    mWindowManager.removeViewImmediate(this);
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                try {
+                    if (getParent() != null) {
+                        mWindowManager.removeViewImmediate(this);
+                    }
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        boolean intercepted = false;
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                intercepted = false;
+                mDownRawX = (int) ev.getRawX();
+                mDownRawY = (int) ev.getRawY();
+                mDownX = (int) ev.getX();
+                mDownY = (int) (ev.getY() + PlayerUtils.getStatusBarHeight(getContext()));
+                break;
+            case MotionEvent.ACTION_MOVE:
+                float absDeltaX = Math.abs(ev.getRawX() - mDownRawX);
+                float absDeltaY = Math.abs(ev.getRawY() - mDownRawY);
+                intercepted = absDeltaX > ViewConfiguration.get(getContext()).getScaledTouchSlop() ||
+                        absDeltaY > ViewConfiguration.get(getContext()).getScaledTouchSlop();
+                break;
+        }
+        return intercepted;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_MOVE:
+                int x = (int) event.getRawX();
+                int y = (int) event.getRawY();
+                mParams.x = x - mDownX;
+                mParams.y = y - mDownY;
+                mWindowManager.updateViewLayout(this, mParams);
+                break;
+        }
+        return super.onTouchEvent(event);
+    }
+}

+ 11 - 0
VideoPlayer/src/main/res/anim/anim_window_enter.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fillAfter="true"
+    android:duration="400">
+    <translate android:fromXDelta="100%p"
+        android:fromYDelta="0"
+        android:toXDelta="0"
+        android:toYDelta="0" />
+    <alpha android:fromAlpha="0"
+        android:toAlpha="1"/>
+</set>

+ 11 - 0
VideoPlayer/src/main/res/anim/anim_window_exit.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fillAfter="true"
+    android:duration="400">
+    <translate android:fromXDelta="0"
+        android:fromYDelta="0"
+        android:toXDelta="100%p"
+        android:toYDelta="0" />
+    <alpha android:fromAlpha="1"
+        android:toAlpha="0"/>
+</set>

BIN
VideoPlayer/src/main/res/drawable-xhdpi/ic_back_close.png


+ 6 - 0
VideoPlayer/src/main/res/drawable/shape_float_window_bg.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@android:color/black"/>
+    <stroke android:color="@color/redTab"
+        android:width="1dp"/>
+</shape>

+ 37 - 0
VideoPlayer/src/main/res/layout/custom_video_player_float.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <ImageView
+        android:id="@+id/iv_start_play"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_gravity="center"
+        android:padding="10dp"
+        android:src="@drawable/selector_play_button" />
+
+    <ProgressBar
+        android:id="@+id/pb_loading"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_gravity="center"
+        android:indeterminateDrawable="@drawable/pb_loading_ring"
+        android:visibility="gone"
+        tools:visibility="visible" />
+    <ImageView
+        android:id="@+id/iv_close"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:layout_gravity="end"
+        android:layout_margin="4dp"
+        android:src="@drawable/ic_back_close" />
+    <ImageView
+        android:id="@+id/iv_skip"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:layout_margin="4dp"
+        android:src="@drawable/ic_player_open" />
+
+</FrameLayout>

+ 7 - 0
VideoPlayer/src/main/res/values/styles.xml

@@ -7,4 +7,11 @@
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:windowBackground">@color/dialog_bg</item>
     </style>
+
+
+    <style name="FloatWindowAnimation">
+        <item name="android:windowEnterAnimation">@anim/anim_window_enter</item>
+        <item name="android:windowExitAnimation">@anim/anim_window_exit</item>
+    </style>
+
 </resources>

+ 3 - 0
app/src/main/AndroidManifest.xml

@@ -95,6 +95,9 @@
         <activity android:name=".oldPlayer.OldActivity"
             android:configChanges="orientation|keyboardHidden|screenSize"
             android:screenOrientation="portrait"/>
+        <activity android:name="org.yczbj.ycvideoplayer.newPlayer.pip.PipActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
     </application>
 
 </manifest>

+ 10 - 1
app/src/main/java/org/yczbj/ycvideoplayer/newPlayer/activity/TypeActivity.java

@@ -16,6 +16,7 @@ import org.yczbj.ycvideoplayer.newPlayer.clarity.ClarityActivity;
 import org.yczbj.ycvideoplayer.newPlayer.danmu.DanmuActivity;
 import org.yczbj.ycvideoplayer.newPlayer.list.ListVideoActivity;
 import org.yczbj.ycvideoplayer.newPlayer.list.TestListActivity;
+import org.yczbj.ycvideoplayer.newPlayer.pip.PipActivity;
 import org.yczbj.ycvideoplayer.newPlayer.surface.TestSurfaceActivity;
 import org.yczbj.ycvideoplayer.newPlayer.tiny.TestFullActivity;
 import org.yczbj.ycvideoplayer.newPlayer.tiny.TinyScreenActivity;
@@ -44,6 +45,8 @@ public class TypeActivity extends AppCompatActivity implements View.OnClickListe
     private TextView mTv31;
     private TextView mTv32;
     private TextView mTv33;
+    private TextView mTv41;
+    private TextView mTv42;
     private TextView mTv43;
     private TextView mTv61;
     private TextView mTv62;
@@ -89,6 +92,8 @@ public class TypeActivity extends AppCompatActivity implements View.OnClickListe
         mTv31 = findViewById(R.id.tv_3_1);
         mTv32 = findViewById(R.id.tv_3_2);
         mTv33 = findViewById(R.id.tv_3_3);
+        mTv41 = findViewById(R.id.tv_4_1);
+        mTv42 = findViewById(R.id.tv_4_2);
         mTv43 = findViewById(R.id.tv_4_3);
         mTv61 = findViewById(R.id.tv_6_1);
         mTv62 = findViewById(R.id.tv_6_2);
@@ -111,6 +116,8 @@ public class TypeActivity extends AppCompatActivity implements View.OnClickListe
         mTv31.setOnClickListener(this);
         mTv32.setOnClickListener(this);
         mTv33.setOnClickListener(this);
+        mTv41.setOnClickListener(this);
+        mTv42.setOnClickListener(this);
         mTv43.setOnClickListener(this);
         mTv61.setOnClickListener(this);
         mTv62.setOnClickListener(this);
@@ -146,7 +153,9 @@ public class TypeActivity extends AppCompatActivity implements View.OnClickListe
             startActivity(new Intent(this, TestFullActivity.class));
         } else if (v == mTv33){
             startActivity(new Intent(this,MultipleActivity.class));
-        } else if (v == mTv43){
+        } else if (v == mTv41){
+            startActivity(new Intent(this, PipActivity.class));
+        }  else if (v == mTv43){
             startActivity(new Intent(this, TinyScreenActivity.class));
         } else if (v == mTv61){
             Intent intent = new Intent(this, TestListActivity.class);

+ 98 - 0
app/src/main/java/org/yczbj/ycvideoplayer/newPlayer/pip/PipActivity.java

@@ -0,0 +1,98 @@
+package org.yczbj.ycvideoplayer.newPlayer.pip;
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import com.bumptech.glide.Glide;
+import org.yczbj.ycvideoplayer.ConstantVideo;
+import org.yczbj.ycvideoplayer.R;
+import org.yczbj.ycvideoplayerlib.player.VideoPlayer;
+import org.yczbj.ycvideoplayerlib.player.VideoViewManager;
+import org.yczbj.ycvideoplayerlib.ui.pip.FloatVideoManager;
+import org.yczbj.ycvideoplayerlib.ui.view.BasisVideoController;
+
+public class PipActivity extends AppCompatActivity{
+
+    private FloatVideoManager mPIPManager;
+    private FrameLayout mPlayerContainer;
+    private Button mBtnFloat;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_pip_video);
+        initFindViewById();
+        initVideoPlayer();
+        initListener();
+    }
+
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mPIPManager.pause();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mPIPManager.resume();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mPIPManager.reset();
+    }
+
+
+    @Override
+    public void onBackPressed() {
+        if (mPIPManager.onBackPress()) return;
+        super.onBackPressed();
+    }
+
+
+    private void initFindViewById() {
+        mPlayerContainer = findViewById(R.id.player_container);
+        mBtnFloat = findViewById(R.id.btn_float);
+    }
+
+    private void initVideoPlayer() {
+        mPIPManager = FloatVideoManager.getInstance(this);
+        VideoPlayer videoView = VideoViewManager.instance().get(FloatVideoManager.PIP);
+        BasisVideoController controller = new BasisVideoController(this);
+        videoView.setVideoController(controller);
+        if (mPIPManager.isStartFloatWindow()) {
+            mPIPManager.stopFloatWindow();
+            controller.setPlayerState(videoView.getCurrentPlayerState());
+            controller.setPlayState(videoView.getCurrentPlayState());
+        } else {
+            mPIPManager.setActClass(PipActivity.class);
+            ImageView thumb = controller.getThumb();
+            Glide.with(this)
+                    .load(R.drawable.image_default)
+                    .placeholder(android.R.color.darker_gray)
+                    .into(thumb);
+            videoView.setUrl(ConstantVideo.VideoPlayerList[0]);
+        }
+        mPlayerContainer.addView(videoView);
+    }
+
+    private void initListener() {
+        mBtnFloat.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mPIPManager.startFloatWindow();
+                mPIPManager.resume();
+            }
+        });
+    }
+
+
+}

+ 25 - 0
app/src/main/res/layout/activity_pip_video.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
+    android:background="@color/whiteBg">
+
+    <FrameLayout
+        android:id="@+id/player_container"
+        android:layout_width="match_parent"
+        android:layout_height="240dp">
+
+    </FrameLayout>
+
+    <Button
+        android:id="@+id/btn_float"
+        android:layout_marginTop="5dp"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="开启悬浮窗视频播放" />
+
+
+</LinearLayout>