当前位置:   article > 正文

Android 基于GSYVideoPlayer实现短视频软件上下滑自动播放视频

gsyvideoplayer

年代久远  , 建议参考github上的Demo实现方式,

链接

CarGuo/GSYVideoPlayer: 视频播放器(IJKplayer、ExoPlayer、MediaPlayer),HTTPS,支持弹幕,外挂字幕,支持滤镜、水印、gif截图,片头广告、中间广告,多个同时播放,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频自带rotation的旋转(90,270之类),重力旋转与手动旋转的同步支持,支持列表播放 ,列表全屏动画,视频加载速度,列表小窗口支持拖动,动画效果,调整比例,多分辨率切换,支持切换播放器,进度条小窗口预览,列表切换详情页面无缝播放,rtsp、concat、mpeg。 (github.com)

先放效果图

两个视频的地址:

  1. private final String mp4_a = "http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4";//玩具总动员
  2. private final String mp4_b = "http://vfx.mtime.cn/Video/2019/03/13/mp4/190313094901111138.mp4"; //抓小偷

我的build.gradle版本
 

  1. compileSdkVersion 29
  2. buildToolsVersion "29.0.0"
  3. defaultConfig {
  4. applicationId "com.klod.t1"
  5. minSdkVersion 21
  6. targetSdkVersion 29
  7. versionCode 1
  8. versionName "1.0"
  9. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  10. }

使用GSYVideoPlayer
 

  1. //完整版引入
  2. implementation 'com.shuyu:GSYVideoPlayer:7.0.1'
  3. implementation 'com.shuyu:gsyVideoPlayer-java:7.0.1'

实现上下滑自动播放视频只要一个Activity (先放主要代码,全部代码会在最下方给出)

    1.layout只有一个RecyclerView 代码就不贴出了

    2.设置RecyclerView  

  1. private void init() {
  2. recyclerView = findViewById(R.id.video_list);
  3. List_Video_Adapter list_video_adapter = new List_Video_Adapter(this, list);
  4. LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
  5. //获取屏幕宽高
  6. DisplayMetrics dm = new DisplayMetrics();
  7. getWindowManager().getDefaultDisplay().getMetrics(dm);
  8. //自定播放帮助类 限定范围为屏幕一半的上下偏移180 括号里不用在意 因为是一个item一个屏幕
  9. scrollCalculatorHelper = new ScrollCalculatorHelper(R.id.list_video_player
  10. , dm.heightPixels / 2 - DpTools.dip2px(this, 180)
  11. , dm.heightPixels / 2 + DpTools.dip2px(this, 180));
  12. //让RecyclerView有ViewPager的翻页效果
  13. PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
  14. pagerSnapHelper.attachToRecyclerView(recyclerView);
  15. //设置LayoutManager和Adapter
  16. recyclerView.setLayoutManager(linearLayoutManager);
  17. recyclerView.setAdapter(list_video_adapter);
  18. //设置滑动监听
  19. recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
  20. //第一个可见视图,最后一个可见视图
  21. int firstVisibleItem, lastVisibleItem;
  22. @Override
  23. public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
  24. super.onScrollStateChanged(recyclerView, newState);
  25. //如果newState的状态==RecyclerView.SCROLL_STATE_IDLE;
  26. //播放对应的视频
  27. scrollCalculatorHelper.onScrollStateChanged(recyclerView, newState);
  28. }
  29. @Override
  30. public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
  31. super.onScrolled(recyclerView, dx, dy);
  32. firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
  33. lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
  34. Log.e("有几个item", firstVisibleItem + " " + lastVisibleItem);
  35. //一屏幕显示一个item 所以固定1
  36. //实时获取设置 当前显示的GSYBaseVideoPlayer的下标
  37. scrollCalculatorHelper.onScroll(recyclerView, firstVisibleItem, lastVisibleItem, 1);
  38. }
  39. });
  40. }

    3.  第2步里的scrollCalculatorHelper  是GSYVideoPlayer里的一个工具类 直接复制拿来用就行
 

  1. package com.klod.t1.utils;
  2. import android.app.AlertDialog;
  3. import android.content.Context;
  4. import android.content.DialogInterface;
  5. import android.graphics.Rect;
  6. import android.os.Handler;
  7. import android.util.Log;
  8. import android.widget.Toast;
  9. import androidx.recyclerview.widget.RecyclerView;
  10. import com.shuyu.gsyvideoplayer.utils.NetworkUtils;
  11. import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer;
  12. /**
  13. * 计算滑动,自动播放的帮助类
  14. * Created by guoshuyu on 2017/11/2.
  15. */
  16. public class ScrollCalculatorHelper {
  17. private int firstVisible = 0;
  18. private int lastVisible = 0;
  19. private int visibleCount = 0;
  20. private int playId;
  21. private int rangeTop;
  22. private int rangeBottom;
  23. private PlayRunnable runnable;
  24. private final String TAG = "ScrollCalculatorHelper";
  25. private Handler playHandler = new Handler();
  26. public ScrollCalculatorHelper(int playId, int rangeTop, int rangeBottom) {
  27. this.playId = playId;
  28. this.rangeTop = rangeTop;
  29. this.rangeBottom = rangeBottom;
  30. }
  31. public void onScrollStateChanged(RecyclerView view, int scrollState) {
  32. switch (scrollState) {
  33. case RecyclerView.SCROLL_STATE_IDLE:
  34. Log.e(TAG,"自动播放执行");
  35. playVideo(view);
  36. break;
  37. }
  38. }
  39. public void onScroll(RecyclerView view, int firstVisibleItem, int lastVisibleItem, int visibleItemCount) {
  40. if (firstVisible == firstVisibleItem) {
  41. return;
  42. }
  43. firstVisible = firstVisibleItem;
  44. lastVisible = lastVisibleItem;
  45. visibleCount = visibleItemCount;
  46. }
  47. private void playVideo(RecyclerView view) {
  48. if (view == null) {
  49. return;
  50. }
  51. RecyclerView.LayoutManager layoutManager = view.getLayoutManager();
  52. GSYBaseVideoPlayer gsyBaseVideoPlayer = null;
  53. boolean needPlay = false;
  54. Log.e(TAG,"自动播放执行 View未空"+visibleCount);
  55. for (int i = 0; i < visibleCount; i++) {
  56. if (layoutManager.getChildAt(i) != null && layoutManager.getChildAt(i).findViewById(playId) != null) {
  57. GSYBaseVideoPlayer player = layoutManager.getChildAt(i).findViewById(playId);
  58. Rect rect = new Rect();
  59. player.getLocalVisibleRect(rect);
  60. int height = player.getHeight();
  61. //说明第一个完全可视
  62. if (rect.top == 0 && rect.bottom == height) {
  63. gsyBaseVideoPlayer = player;
  64. if ((player.getCurrentPlayer().getCurrentState() == GSYBaseVideoPlayer.CURRENT_STATE_NORMAL
  65. || player.getCurrentPlayer().getCurrentState() == GSYBaseVideoPlayer.CURRENT_STATE_ERROR)) {
  66. needPlay = true;
  67. }
  68. break;
  69. }
  70. }
  71. }
  72. if (gsyBaseVideoPlayer != null && needPlay) {
  73. if (runnable != null) {
  74. GSYBaseVideoPlayer tmpPlayer = runnable.gsyBaseVideoPlayer;
  75. playHandler.removeCallbacks(runnable);
  76. runnable = null;
  77. if (tmpPlayer == gsyBaseVideoPlayer) {
  78. return;
  79. }
  80. }
  81. Log.e(TAG,"自动播放执行 开始");
  82. runnable = new PlayRunnable(gsyBaseVideoPlayer);
  83. //降低频率
  84. playHandler.postDelayed(runnable, 400);
  85. }
  86. }
  87. private class PlayRunnable implements Runnable {
  88. GSYBaseVideoPlayer gsyBaseVideoPlayer;
  89. public PlayRunnable(GSYBaseVideoPlayer gsyBaseVideoPlayer) {
  90. this.gsyBaseVideoPlayer = gsyBaseVideoPlayer;
  91. }
  92. @Override
  93. public void run() {
  94. boolean inPosition = false;
  95. //如果未播放,需要播放
  96. if (gsyBaseVideoPlayer != null) {
  97. int[] screenPosition = new int[2];
  98. gsyBaseVideoPlayer.getLocationOnScreen(screenPosition);
  99. int halfHeight = gsyBaseVideoPlayer.getHeight() / 2;
  100. int rangePosition = screenPosition[1] + halfHeight;
  101. //中心点在播放区域内
  102. if (rangePosition >= rangeTop && rangePosition <= rangeBottom) {
  103. inPosition = true;
  104. }
  105. if (inPosition) {
  106. startPlayLogic(gsyBaseVideoPlayer, gsyBaseVideoPlayer.getContext());
  107. //gsyBaseVideoPlayer.startPlayLogic();
  108. }
  109. }
  110. }
  111. }
  112. /***************************************自动播放的点击播放确认******************************************/
  113. private void startPlayLogic(GSYBaseVideoPlayer gsyBaseVideoPlayer, Context context) {
  114. if (!com.shuyu.gsyvideoplayer.utils.CommonUtil.isWifiConnected(context)) {
  115. //这里判断是否wifi
  116. showWifiDialog(gsyBaseVideoPlayer, context);
  117. return;
  118. }
  119. gsyBaseVideoPlayer.startPlayLogic();
  120. }
  121. private void showWifiDialog(final GSYBaseVideoPlayer gsyBaseVideoPlayer, Context context) {
  122. if (!NetworkUtils.isAvailable(context)) {
  123. Toast.makeText(context, context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.no_net), Toast.LENGTH_LONG).show();
  124. return;
  125. }
  126. AlertDialog.Builder builder = new AlertDialog.Builder(context);
  127. builder.setMessage(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi));
  128. builder.setPositiveButton(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi_confirm), new DialogInterface.OnClickListener() {
  129. @Override
  130. public void onClick(DialogInterface dialog, int which) {
  131. dialog.dismiss();
  132. gsyBaseVideoPlayer.startPlayLogic();
  133. }
  134. });
  135. builder.setNegativeButton(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi_cancel), new DialogInterface.OnClickListener() {
  136. @Override
  137. public void onClick(DialogInterface dialog, int which) {
  138. dialog.dismiss();
  139. }
  140. });
  141. builder.create().show();
  142. }
  143. }

接下来做RecyclerView适配器
适配器的Item就一个StandardGSYVideoPlayer

xml:

  1. <com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
  2. android:id="@+id/list_video_player"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:layout_centerVertical="true"
  6. android:paddingBottom="20dp"
  7. />

adapter:

  1. package com.klod.t1.adapter;
  2. import android.content.Context;
  3. import android.view.LayoutInflater;
  4. import android.view.View;
  5. import android.view.ViewGroup;
  6. import androidx.annotation.NonNull;
  7. import androidx.recyclerview.widget.RecyclerView;
  8. import com.klod.t1.R;
  9. import com.klod.t1.bean.Video_Bean;
  10. import com.shuyu.gsyvideoplayer.GSYVideoManager;
  11. import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder;
  12. import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack;
  13. import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
  14. import java.util.HashMap;
  15. import java.util.List;
  16. import java.util.Map;
  17. public class List_Video_Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
  18. private Context context;
  19. private List<Video_Bean> list;
  20. public static final String TAG = "ListNormalAdapter22";
  21. private GSYVideoOptionBuilder gsyVideoOptionBuilder;
  22. public List_Video_Adapter(Context context,List<Video_Bean> list) {
  23. this.context = context;
  24. this.list = list;
  25. }
  26. @NonNull
  27. @Override
  28. public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  29. return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_video_item,parent,false));
  30. }
  31. @Override
  32. public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
  33. ViewHolder vh = (ViewHolder) holder;
  34. Map<String, String> header = new HashMap<>();
  35. header.put("ee", "33");
  36. //配置视频播放器参数
  37. gsyVideoOptionBuilder
  38. .setIsTouchWiget(false)
  39. .setUrl(list.get(position).getUrl())
  40. .setVideoTitle(list.get(position).getTitle())
  41. .setCacheWithPlay(false)
  42. .setRotateViewAuto(true)
  43. .setLockLand(true)
  44. .setPlayTag(TAG)
  45. .setMapHeadData(header)
  46. .setShowFullAnimation(true)
  47. .setNeedLockFull(true)
  48. .setPlayPosition(position)
  49. .setReleaseWhenLossAudio(false)
  50. .setVideoAllCallBack(new GSYSampleCallBack() {
  51. @Override
  52. public void onPrepared(String url, Object... objects) {
  53. super.onPrepared(url, objects);
  54. if (!vh.standardGSYVideoPlayer.isIfCurrentIsFullscreen()) {
  55. //静音
  56. //GSYVideoManager.instance().setNeedMute(true);
  57. }
  58. }
  59. @Override
  60. public void onQuitFullscreen(String url, Object... objects) {
  61. super.onQuitFullscreen(url, objects);
  62. //全屏不静音
  63. //GSYVideoManager.instance().setNeedMute(true);
  64. }
  65. @Override
  66. public void onEnterFullscreen(String url, Object... objects) {
  67. super.onEnterFullscreen(url, objects);
  68. GSYVideoManager.instance().setNeedMute(false);
  69. vh.standardGSYVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String)objects[0]);
  70. }
  71. }).build(vh.standardGSYVideoPlayer);
  72. //设置返回键
  73. vh.standardGSYVideoPlayer.getBackButton().setVisibility(View.GONE);
  74. //设置全屏按键功能
  75. vh.standardGSYVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
  76. @Override
  77. public void onClick(View v) {
  78. vh.standardGSYVideoPlayer.startWindowFullscreen(context, false, true);
  79. }
  80. });
  81. //实现第一个视频自动播放
  82. if(position==0){
  83. vh.standardGSYVideoPlayer.startPlayLogic();
  84. }
  85. }
  86. @Override
  87. public int getItemCount() {
  88. return list==null?0:list.size();
  89. }
  90. class ViewHolder extends RecyclerView.ViewHolder{
  91. private StandardGSYVideoPlayer standardGSYVideoPlayer;
  92. public ViewHolder(@NonNull View itemView) {
  93. super(itemView);
  94. gsyVideoOptionBuilder = new GSYVideoOptionBuilder();
  95. standardGSYVideoPlayer = itemView.findViewById(R.id.list_video_player);
  96. }
  97. }
  98. }

到这就实现了短视频软件上下滑自动播放视频
总体流程:
写布局=>写适配器=>写Activity逻辑
 

给出Activity全部代码:

  1. package com.klod.t1.activity;
  2. import android.content.res.Configuration;
  3. import android.os.Bundle;
  4. import android.util.DisplayMetrics;
  5. import android.util.Log;
  6. import android.view.WindowManager;
  7. import androidx.annotation.NonNull;
  8. import androidx.annotation.Nullable;
  9. import androidx.appcompat.app.AppCompatActivity;
  10. import androidx.core.content.ContextCompat;
  11. import androidx.recyclerview.widget.LinearLayoutManager;
  12. import androidx.recyclerview.widget.PagerSnapHelper;
  13. import androidx.recyclerview.widget.RecyclerView;
  14. import com.klod.t1.R;
  15. import com.klod.t1.adapter.List_Video_Adapter;
  16. import com.klod.t1.bean.Video_Bean;
  17. import com.klod.t1.utils.DpTools;
  18. import com.klod.t1.utils.ScrollCalculatorHelper;
  19. import com.klod.t1.utils.StatusBarUtil;
  20. import com.shuyu.gsyvideoplayer.GSYVideoManager;
  21. import java.util.ArrayList;
  22. import java.util.List;
  23. public class List_Video_Activity extends AppCompatActivity {
  24. private RecyclerView recyclerView;
  25. private final String mp4_a = "http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4";//玩具总动员
  26. private final String mp4_b = "http://vfx.mtime.cn/Video/2019/03/13/mp4/190313094901111138.mp4"; //抓小偷
  27. private List<Video_Bean> list;
  28. //控制滚动播放
  29. ScrollCalculatorHelper scrollCalculatorHelper;
  30. @Override
  31. protected void onCreate(@Nullable Bundle savedInstanceState) {
  32. super.onCreate(savedInstanceState);
  33. setContentView(R.layout.list_video_activity);
  34. StatusBarUtil.setColor(this, getResources().getColor(R.color.HaiPaiBlack));
  35. initData();
  36. init();
  37. }
  38. private void initData() {
  39. //视频数据
  40. list = new ArrayList<>();
  41. for (int i = 0; i < 10; i++) {
  42. Video_Bean video_bean = new Video_Bean();
  43. if (i % 2 == 0) {
  44. video_bean.setUrl(mp4_a);
  45. } else {
  46. video_bean.setUrl(mp4_b);
  47. }
  48. video_bean.setBitmap(ContextCompat.getDrawable(this, R.drawable.image));
  49. video_bean.setTitle("傀儡偶段のVideo " + i);
  50. list.add(video_bean);
  51. }
  52. }
  53. private void init() {
  54. recyclerView = findViewById(R.id.video_list);
  55. List_Video_Adapter list_video_adapter = new List_Video_Adapter(this, list);
  56. LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
  57. //获取屏幕宽高
  58. DisplayMetrics dm = new DisplayMetrics();
  59. getWindowManager().getDefaultDisplay().getMetrics(dm);
  60. //自定播放帮助类 限定范围为屏幕一半的上下偏移180 括号里不用在意 因为是一个item一个屏幕
  61. scrollCalculatorHelper = new ScrollCalculatorHelper(R.id.list_video_player
  62. , dm.heightPixels / 2 - DpTools.dip2px(this, 180)
  63. , dm.heightPixels / 2 + DpTools.dip2px(this, 180));
  64. //让RecyclerView有ViewPager的翻页效果
  65. PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
  66. pagerSnapHelper.attachToRecyclerView(recyclerView);
  67. //设置LayoutManager和Adapter
  68. recyclerView.setLayoutManager(linearLayoutManager);
  69. recyclerView.setAdapter(list_video_adapter);
  70. //设置滑动监听
  71. recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
  72. //第一个可见视图,最后一个可见视图
  73. int firstVisibleItem, lastVisibleItem;
  74. @Override
  75. public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
  76. super.onScrollStateChanged(recyclerView, newState);
  77. //如果newState的状态==RecyclerView.SCROLL_STATE_IDLE;
  78. //播放对应的视频
  79. scrollCalculatorHelper.onScrollStateChanged(recyclerView, newState);
  80. }
  81. @Override
  82. public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
  83. super.onScrolled(recyclerView, dx, dy);
  84. firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
  85. lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
  86. Log.e("有几个item", firstVisibleItem + " " + lastVisibleItem);
  87. //一屏幕显示一个item 所以固定1
  88. //实时获取设置 当前显示的GSYBaseVideoPlayer的下标
  89. scrollCalculatorHelper.onScroll(recyclerView, firstVisibleItem, lastVisibleItem, 1);
  90. }
  91. });
  92. }
  93. @Override
  94. protected void onResume() {
  95. super.onResume();
  96. GSYVideoManager.onResume();
  97. }
  98. @Override
  99. protected void onPause() {
  100. super.onPause();
  101. GSYVideoManager.onPause();
  102. }
  103. @Override
  104. protected void onDestroy() {
  105. super.onDestroy();
  106. GSYVideoManager.releaseAllVideos();
  107. }
  108. @Override
  109. public void onConfigurationChanged(Configuration newConfig) {
  110. Configuration mConfiguration = this.getResources().getConfiguration();
  111. int ori = mConfiguration.orientation;
  112. if (ori == Configuration.ORIENTATION_LANDSCAPE) {
  113. getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //隐藏状态栏
  114. } else if (ori == Configuration.ORIENTATION_PORTRAIT) {
  115. //当前为竖屏
  116. getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //显示状态栏
  117. }
  118. super.onConfigurationChanged(newConfig);
  119. }
  120. }

还有一个单位转换类:

  1. public class DpTools {
  2. /**
  3. * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
  4. */
  5. public static int dip2px(Context context, float dpValue) {
  6. final float scale = context.getResources().getDisplayMetrics().density;
  7. return (int) (dpValue * scale + 0.5f);
  8. }
  9. /**
  10. * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
  11. */
  12. public static int px2dip(Context context, float pxValue) {
  13. final float scale = context.getResources().getDisplayMetrics().density;
  14. return (int) (pxValue / scale + 0.5f);
  15. }
  16. }

补上 Bean的代码

  1. public class Video_Bean implements Serializable {
  2. /**
  3. * 默认
  4. */
  5. public static final long serialVersionUID = 1L;
  6. private String url;
  7. private String title;
  8. private Drawable bitmap;
  9. public Video_Bean() {
  10. }
  11. public Video_Bean(String url, String title, Drawable bitmap) {
  12. this.url = url;
  13. this.bitmap = bitmap;
  14. this.title = title;
  15. }
  16. public String getUrl() {
  17. return url;
  18. }
  19. public void setUrl(String url) {
  20. this.url = url;
  21. }
  22. public String getTitle() {
  23. return title;
  24. }
  25. public void setTitle(String title) {
  26. this.title = title;
  27. }
  28. public Drawable getBitmap() {
  29. return bitmap;
  30. }
  31. public void setBitmap(Drawable bitmap) {
  32. this.bitmap = bitmap;
  33. }
  34. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/532450
推荐阅读
相关标签
  

闽ICP备14008679号