年代久远 , 建议参考github上的Demo实现方式,
链接
先放效果图
两个视频的地址:
private final String mp4_a = "http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4";//玩具总动员
private final String mp4_b = "http://vfx.mtime.cn/Video/2019/03/13/mp4/190313094901111138.mp4"; //抓小偷
我的build.gradle版本
compileSdkVersion 29
buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.klod.t1"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
使用GSYVideoPlayer
//完整版引入
implementation 'com.shuyu:GSYVideoPlayer:7.0.1'
implementation 'com.shuyu:gsyVideoPlayer-java:7.0.1'
实现上下滑自动播放视频只要一个Activity (先放主要代码,全部代码会在最下方给出)
1.layout只有一个RecyclerView 代码就不贴出了
2.设置RecyclerView
private void init() {
recyclerView = findViewById(R.id.video_list);
List_Video_Adapter list_video_adapter = new List_Video_Adapter(this, list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//获取屏幕宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//自定播放帮助类 限定范围为屏幕一半的上下偏移180 括号里不用在意 因为是一个item一个屏幕
scrollCalculatorHelper = new ScrollCalculatorHelper(R.id.list_video_player
, dm.heightPixels / 2 - DpTools.dip2px(this, 180)
, dm.heightPixels / 2 + DpTools.dip2px(this, 180));
//让RecyclerView有ViewPager的翻页效果
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
pagerSnapHelper.attachToRecyclerView(recyclerView);
//设置LayoutManager和Adapter
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(list_video_adapter);
//设置滑动监听
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
//第一个可见视图,最后一个可见视图
int firstVisibleItem, lastVisibleItem;
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//如果newState的状态==RecyclerView.SCROLL_STATE_IDLE;
//播放对应的视频
scrollCalculatorHelper.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
Log.e("有几个item", firstVisibleItem + " " + lastVisibleItem);
//一屏幕显示一个item 所以固定1
//实时获取设置 当前显示的GSYBaseVideoPlayer的下标
scrollCalculatorHelper.onScroll(recyclerView, firstVisibleItem, lastVisibleItem, 1);
}
});
}
3. 第2步里的scrollCalculatorHelper 是GSYVideoPlayer里的一个工具类 直接复制拿来用就行
package com.klod.t1.utils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Rect;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import com.shuyu.gsyvideoplayer.utils.NetworkUtils;
import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer;
/**
* 计算滑动,自动播放的帮助类
* Created by guoshuyu on 2017/11/2.
*/
public class ScrollCalculatorHelper {
private int firstVisible = 0;
private int lastVisible = 0;
private int visibleCount = 0;
private int playId;
private int rangeTop;
private int rangeBottom;
private PlayRunnable runnable;
private final String TAG = "ScrollCalculatorHelper";
private Handler playHandler = new Handler();
public ScrollCalculatorHelper(int playId, int rangeTop, int rangeBottom) {
this.playId = playId;
this.rangeTop = rangeTop;
this.rangeBottom = rangeBottom;
}
public void onScrollStateChanged(RecyclerView view, int scrollState) {
switch (scrollState) {
case RecyclerView.SCROLL_STATE_IDLE:
Log.e(TAG,"自动播放执行");
playVideo(view);
break;
}
}
public void onScroll(RecyclerView view, int firstVisibleItem, int lastVisibleItem, int visibleItemCount) {
if (firstVisible == firstVisibleItem) {
return;
}
firstVisible = firstVisibleItem;
lastVisible = lastVisibleItem;
visibleCount = visibleItemCount;
}
private void playVideo(RecyclerView view) {
if (view == null) {
return;
}
RecyclerView.LayoutManager layoutManager = view.getLayoutManager();
GSYBaseVideoPlayer gsyBaseVideoPlayer = null;
boolean needPlay = false;
Log.e(TAG,"自动播放执行 View未空"+visibleCount);
for (int i = 0; i < visibleCount; i++) {
if (layoutManager.getChildAt(i) != null && layoutManager.getChildAt(i).findViewById(playId) != null) {
GSYBaseVideoPlayer player = layoutManager.getChildAt(i).findViewById(playId);
Rect rect = new Rect();
player.getLocalVisibleRect(rect);
int height = player.getHeight();
//说明第一个完全可视
if (rect.top == 0 && rect.bottom == height) {
gsyBaseVideoPlayer = player;
if ((player.getCurrentPlayer().getCurrentState() == GSYBaseVideoPlayer.CURRENT_STATE_NORMAL
|| player.getCurrentPlayer().getCurrentState() == GSYBaseVideoPlayer.CURRENT_STATE_ERROR)) {
needPlay = true;
}
break;
}
}
}
if (gsyBaseVideoPlayer != null && needPlay) {
if (runnable != null) {
GSYBaseVideoPlayer tmpPlayer = runnable.gsyBaseVideoPlayer;
playHandler.removeCallbacks(runnable);
runnable = null;
if (tmpPlayer == gsyBaseVideoPlayer) {
return;
}
}
Log.e(TAG,"自动播放执行 开始");
runnable = new PlayRunnable(gsyBaseVideoPlayer);
//降低频率
playHandler.postDelayed(runnable, 400);
}
}
private class PlayRunnable implements Runnable {
GSYBaseVideoPlayer gsyBaseVideoPlayer;
public PlayRunnable(GSYBaseVideoPlayer gsyBaseVideoPlayer) {
this.gsyBaseVideoPlayer = gsyBaseVideoPlayer;
}
@Override
public void run() {
boolean inPosition = false;
//如果未播放,需要播放
if (gsyBaseVideoPlayer != null) {
int[] screenPosition = new int[2];
gsyBaseVideoPlayer.getLocationOnScreen(screenPosition);
int halfHeight = gsyBaseVideoPlayer.getHeight() / 2;
int rangePosition = screenPosition[1] + halfHeight;
//中心点在播放区域内
if (rangePosition >= rangeTop && rangePosition <= rangeBottom) {
inPosition = true;
}
if (inPosition) {
startPlayLogic(gsyBaseVideoPlayer, gsyBaseVideoPlayer.getContext());
//gsyBaseVideoPlayer.startPlayLogic();
}
}
}
}
/***************************************自动播放的点击播放确认******************************************/
private void startPlayLogic(GSYBaseVideoPlayer gsyBaseVideoPlayer, Context context) {
if (!com.shuyu.gsyvideoplayer.utils.CommonUtil.isWifiConnected(context)) {
//这里判断是否wifi
showWifiDialog(gsyBaseVideoPlayer, context);
return;
}
gsyBaseVideoPlayer.startPlayLogic();
}
private void showWifiDialog(final GSYBaseVideoPlayer gsyBaseVideoPlayer, Context context) {
if (!NetworkUtils.isAvailable(context)) {
Toast.makeText(context, context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.no_net), Toast.LENGTH_LONG).show();
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi));
builder.setPositiveButton(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi_confirm), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
gsyBaseVideoPlayer.startPlayLogic();
}
});
builder.setNegativeButton(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}
接下来做RecyclerView适配器
适配器的Item就一个StandardGSYVideoPlayer
xml:
<com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
android:id="@+id/list_video_player"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:paddingBottom="20dp"
/>
adapter:
package com.klod.t1.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.klod.t1.R;
import com.klod.t1.bean.Video_Bean;
import com.shuyu.gsyvideoplayer.GSYVideoManager;
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder;
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack;
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class List_Video_Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<Video_Bean> list;
public static final String TAG = "ListNormalAdapter22";
private GSYVideoOptionBuilder gsyVideoOptionBuilder;
public List_Video_Adapter(Context context,List<Video_Bean> list) {
this.context = context;
this.list = list;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_video_item,parent,false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ViewHolder vh = (ViewHolder) holder;
Map<String, String> header = new HashMap<>();
header.put("ee", "33");
//配置视频播放器参数
gsyVideoOptionBuilder
.setIsTouchWiget(false)
.setUrl(list.get(position).getUrl())
.setVideoTitle(list.get(position).getTitle())
.setCacheWithPlay(false)
.setRotateViewAuto(true)
.setLockLand(true)
.setPlayTag(TAG)
.setMapHeadData(header)
.setShowFullAnimation(true)
.setNeedLockFull(true)
.setPlayPosition(position)
.setReleaseWhenLossAudio(false)
.setVideoAllCallBack(new GSYSampleCallBack() {
@Override
public void onPrepared(String url, Object... objects) {
super.onPrepared(url, objects);
if (!vh.standardGSYVideoPlayer.isIfCurrentIsFullscreen()) {
//静音
//GSYVideoManager.instance().setNeedMute(true);
}
}
@Override
public void onQuitFullscreen(String url, Object... objects) {
super.onQuitFullscreen(url, objects);
//全屏不静音
//GSYVideoManager.instance().setNeedMute(true);
}
@Override
public void onEnterFullscreen(String url, Object... objects) {
super.onEnterFullscreen(url, objects);
GSYVideoManager.instance().setNeedMute(false);
vh.standardGSYVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String)objects[0]);
}
}).build(vh.standardGSYVideoPlayer);
//设置返回键
vh.standardGSYVideoPlayer.getBackButton().setVisibility(View.GONE);
//设置全屏按键功能
vh.standardGSYVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
vh.standardGSYVideoPlayer.startWindowFullscreen(context, false, true);
}
});
//实现第一个视频自动播放
if(position==0){
vh.standardGSYVideoPlayer.startPlayLogic();
}
}
@Override
public int getItemCount() {
return list==null?0:list.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
private StandardGSYVideoPlayer standardGSYVideoPlayer;
public ViewHolder(@NonNull View itemView) {
super(itemView);
gsyVideoOptionBuilder = new GSYVideoOptionBuilder();
standardGSYVideoPlayer = itemView.findViewById(R.id.list_video_player);
}
}
}
到这就实现了短视频软件上下滑自动播放视频
总体流程:
写布局=>写适配器=>写Activity逻辑
给出Activity全部代码:
package com.klod.t1.activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.klod.t1.R;
import com.klod.t1.adapter.List_Video_Adapter;
import com.klod.t1.bean.Video_Bean;
import com.klod.t1.utils.DpTools;
import com.klod.t1.utils.ScrollCalculatorHelper;
import com.klod.t1.utils.StatusBarUtil;
import com.shuyu.gsyvideoplayer.GSYVideoManager;
import java.util.ArrayList;
import java.util.List;
public class List_Video_Activity extends AppCompatActivity {
private RecyclerView recyclerView;
private final String mp4_a = "http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4";//玩具总动员
private final String mp4_b = "http://vfx.mtime.cn/Video/2019/03/13/mp4/190313094901111138.mp4"; //抓小偷
private List<Video_Bean> list;
//控制滚动播放
ScrollCalculatorHelper scrollCalculatorHelper;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_video_activity);
StatusBarUtil.setColor(this, getResources().getColor(R.color.HaiPaiBlack));
initData();
init();
}
private void initData() {
//视频数据
list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Video_Bean video_bean = new Video_Bean();
if (i % 2 == 0) {
video_bean.setUrl(mp4_a);
} else {
video_bean.setUrl(mp4_b);
}
video_bean.setBitmap(ContextCompat.getDrawable(this, R.drawable.image));
video_bean.setTitle("傀儡偶段のVideo " + i);
list.add(video_bean);
}
}
private void init() {
recyclerView = findViewById(R.id.video_list);
List_Video_Adapter list_video_adapter = new List_Video_Adapter(this, list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//获取屏幕宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//自定播放帮助类 限定范围为屏幕一半的上下偏移180 括号里不用在意 因为是一个item一个屏幕
scrollCalculatorHelper = new ScrollCalculatorHelper(R.id.list_video_player
, dm.heightPixels / 2 - DpTools.dip2px(this, 180)
, dm.heightPixels / 2 + DpTools.dip2px(this, 180));
//让RecyclerView有ViewPager的翻页效果
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
pagerSnapHelper.attachToRecyclerView(recyclerView);
//设置LayoutManager和Adapter
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(list_video_adapter);
//设置滑动监听
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
//第一个可见视图,最后一个可见视图
int firstVisibleItem, lastVisibleItem;
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//如果newState的状态==RecyclerView.SCROLL_STATE_IDLE;
//播放对应的视频
scrollCalculatorHelper.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
Log.e("有几个item", firstVisibleItem + " " + lastVisibleItem);
//一屏幕显示一个item 所以固定1
//实时获取设置 当前显示的GSYBaseVideoPlayer的下标
scrollCalculatorHelper.onScroll(recyclerView, firstVisibleItem, lastVisibleItem, 1);
}
});
}
@Override
protected void onResume() {
super.onResume();
GSYVideoManager.onResume();
}
@Override
protected void onPause() {
super.onPause();
GSYVideoManager.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
GSYVideoManager.releaseAllVideos();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
Configuration mConfiguration = this.getResources().getConfiguration();
int ori = mConfiguration.orientation;
if (ori == Configuration.ORIENTATION_LANDSCAPE) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //隐藏状态栏
} else if (ori == Configuration.ORIENTATION_PORTRAIT) {
//当前为竖屏
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //显示状态栏
}
super.onConfigurationChanged(newConfig);
}
}
还有一个单位转换类:
public class DpTools {
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
补上 Bean的代码
public class Video_Bean implements Serializable {
/**
* 默认
*/
public static final long serialVersionUID = 1L;
private String url;
private String title;
private Drawable bitmap;
public Video_Bean() {
}
public Video_Bean(String url, String title, Drawable bitmap) {
this.url = url;
this.bitmap = bitmap;
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Drawable getBitmap() {
return bitmap;
}
public void setBitmap(Drawable bitmap) {
this.bitmap = bitmap;
}
}