在很多播放视频的APP中都有在列表中播放视频的效果,当点击播放的时候,在列表中播放,当视频列表滑动出屏幕的时候,就在屏幕的右下角播放。大致效果如下图:
这里写图片描述
-
主要思路
- 在和RecyclerView的同级布局文件中,在右下角放置一个隐藏FrameLayout,当正在播放的列表滑出界面的时候,将右下角的FragmeLayout设置为显示,并将播放的SurfaceView添加到右下角的FragmeLayout播放。
- 在列表的ViewHolder布局文件中放置一个FragmeLayout,当点击播放按钮时,将SurfaceView添加到FragmentLayout中播放。
- 为RecyclerView设置addOnChildAttachStateChangeListener事件,这个监听有两个重要的方法
/** *当添加子View时回调 */ public void onChildViewAttachedToWindow(View view); /** *当移除子View时回调 */ public void onChildViewDetachedFromWindow(View view)
-
首先看下主界面布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
<!-- 右下角的FragmeLayout -->
<FrameLayout
android:id="@+id/video_root_fl"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#000"
android:visibility="gone" />
<!--全屏播放的FragmeLayout-->
<FrameLayout
android:id="@+id/video_full_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</RelativeLayout>
可以在布局文件中看到,在右下角中放置了一个隐藏的FrameLayout,当正在播放的列表滑出界面时我们会使用这个FrameLayout来放置播放视频的SurfaceView。
- 在RecyclerView中的item布局文件中也有一个FrameLayout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/item_cardview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="10dp"
android:background="#fff"
android:elevation="8dp"
android:padding="5dp"
app:cardBackgroundColor="#fff"
app:cardCornerRadius="5dp">
<!--列表播放使用的FrameLayout-->
<FrameLayout
android:id="@+id/item_video_root_fl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<ImageView
android:id="@+id/item_imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<ImageView
android:id="@+id/item_image_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_play_circle_outline_white_48dp" />
</android.support.v7.widget.CardView>
item中这个FrameLayout用于点击列表中播放按钮将要播放的SurfaceView添加到这个FrameLayout中
- 为RecyclerView添加addOnChildAttachStateChangeListener监听,当正在播放的item滑出界面时会回调onChildViewDetachedFromWindow这个方法,我们在这个方法中判断如果FragmeLayout中有视频播放,将右下角的FrameLayout设置为显示,移除item布局中的SurfaceView并将其添加到右下角的FrameLayout,将记录这个item的位置,当再次将这个item滑动到界面中时,会回调onChildViewAttachedToWindow这个方法。同理再将这个右下角中的FrameLayout中的SurfaceView移除并设置为隐藏,再将SurfaceView添加到item中的FrameLayout播放。
//为RecyclerView添加addOnChildAttachStateChangeListener监听
recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
if (videoPosition == -1 || videoRootViewFl.getVisibility() != View.VISIBLE) {
return;
}
if (videoPosition == recyclerView.getChildAdapterPosition(view)) {
videoPosition = -1;
showVideo(view, VIDEO_PATH);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
if (videoView == null || videoRootViewFl.getVisibility() == View.VISIBLE) return;
View v = view.findViewById(R.id.item_video_root_fl);
if (v != null) {
FrameLayout fl = (FrameLayout) v;
videoPosition = recyclerView.getChildAdapterPosition(view);
if (fl.getChildCount() > 0) {
fl.removeAllViews();
int position = 0;
if (videoView.isPlaying()) {
position = videoView.getPosition();
videoView.stop();
}
videoRootViewFl.setVisibility(View.VISIBLE);
videoRootViewFl.removeAllViews();
lastView = videoRootViewFl;
videoRootViewFl.addView(videoView, new ViewGroup.LayoutParams(-1, -1));
videoView.setVideoPath(VIDEO_PATH);
videoView.start();
videoView.seekTo(position);
// if (videoView.isPause()) {
// videoView.resume();
// }
}
fl.setVisibility(View.GONE);
}
v = view.findViewById(R.id.item_imageview);
if (v != null) {
if (v.getVisibility() != View.VISIBLE) {
v.setVisibility(View.VISIBLE);
}
}
v = view.findViewById(R.id.item_image_play);
if (v != null) {
if (v.getVisibility() != View.VISIBLE) {
v.setVisibility(View.VISIBLE);
}
}
}
});
完整代码
传送门
网友评论