Android中如何使用ViewPager2实现类似TikTok的上下滑动切换视频功能
使用Java + ViewPager2 实现TikTok风格上下滑动视频播放
以下方案适配Android Studio 2020.3.1.25版本,全程使用Java语言实现:
1. 导入必要依赖
首先打开模块级build.gradle文件,在dependencies块中添加如下依赖:
// ViewPager2 核心依赖 implementation "androidx.viewpager2:viewpager2:1.0.0" // ExoPlayer 视频播放依赖,Google官方推荐的视频播放组件 implementation "com.google.android.exoplayer:exoplayer:2.18.7"
添加完成后点击同步Gradle即可。
2. 编写核心布局文件
2.1 主页面布局(activity_main.xml)
只需要一个全屏的ViewPager2,设置滑动方向为垂直:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewPager2" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"/> </androidx.constraintlayout.widget.ConstraintLayout>
2.2 单个视频item布局(item_video.xml)
每个页面只需要一个占满全屏的ExoPlayer的PlayerView:
<?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"> <com.google.android.exoplayer2.ui.PlayerView android:id="@+id/playerView" android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true" app:use_controller="false"/> </FrameLayout>
3. 定义视频数据实体类
创建VideoBean.java用来存储每个视频的相关信息:
public class VideoBean { private String videoUrl; private String coverUrl; public VideoBean(String videoUrl, String coverUrl) { this.videoUrl = videoUrl; this.coverUrl = coverUrl; } // 省略getter、setter方法 }
4. 实现ViewPager2适配器
ViewPager2的适配器直接继承RecyclerView.Adapter即可:
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHolder> { private List<VideoBean> videoList; private ExoPlayer currentPlayer; public VideoAdapter(List<VideoBean> videoList) { this.videoList = videoList; } @NonNull @Override public VideoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false); return new VideoViewHolder(view); } @Override public void onBindViewHolder(@NonNull VideoViewHolder holder, int position) { // 这里只绑定数据,播放逻辑放到页面选中时处理,避免同时加载多个视频 holder.videoUrl = videoList.get(position).getVideoUrl(); } @Override public int getItemCount() { return videoList.size(); } // 页面选中时调用此方法播放当前视频 public void playVideo(int position, VideoViewHolder holder) { // 先释放之前的播放器资源 if (currentPlayer != null) { currentPlayer.release(); } // 初始化新的播放器 Context context = holder.itemView.getContext(); currentPlayer = new ExoPlayer.Builder(context).build(); holder.playerView.setPlayer(currentPlayer); // 设置播放源 MediaItem mediaItem = MediaItem.fromUri(holder.videoUrl); currentPlayer.setMediaItem(mediaItem); currentPlayer.setRepeatMode(Player.REPEAT_MODE_ONE); currentPlayer.prepare(); currentPlayer.play(); } // 释放所有播放器资源 public void releasePlayer() { if (currentPlayer != null) { currentPlayer.release(); currentPlayer = null; } } public static class VideoViewHolder extends RecyclerView.ViewHolder { PlayerView playerView; String videoUrl; public VideoViewHolder(@NonNull View itemView) { super(itemView); playerView = itemView.findViewById(R.id.playerView); } } }
5. 主页面逻辑实现
在MainActivity.java中绑定适配器,添加页面切换监听:
public class MainActivity extends AppCompatActivity { private ViewPager2 viewPager2; private VideoAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager2 = findViewById(R.id.viewPager2); // 模拟测试数据,替换为你自己的视频地址 List<VideoBean> videoList = new ArrayList<>(); videoList.add(new VideoBean("你的视频地址1", "")); videoList.add(new VideoBean("你的视频地址2", "")); videoList.add(new VideoBean("你的视频地址3", "")); // 设置适配器 adapter = new VideoAdapter(videoList); viewPager2.setAdapter(adapter); // 配置预加载页数,提升滑动体验 viewPager2.setOffscreenPageLimit(1); // 添加页面切换监听 viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); // 获取当前选中的ViewHolder,播放视频 RecyclerView recyclerView = (RecyclerView) viewPager2.getChildAt(0); VideoAdapter.VideoViewHolder viewHolder = (VideoAdapter.VideoViewHolder) recyclerView.findViewHolderForAdapterPosition(position); if (viewHolder != null) { adapter.playVideo(position, viewHolder); } } }); // 首次进入自动播放第一个视频 viewPager2.post(() -> adapter.playVideo(0, (VideoAdapter.VideoViewHolder) ((RecyclerView)viewPager2.getChildAt(0)).findViewHolderForAdapterPosition(0))); } @Override protected void onPause() { super.onPause(); if (adapter != null) { adapter.releasePlayer(); } } @Override protected void onDestroy() { super.onDestroy(); if (adapter != null) { adapter.releasePlayer(); } } }
可选优化点
- 给PlayerView添加封面图,避免视频加载完成前出现黑屏
- 添加缓冲加载提示,提升弱网环境下的用户体验
- 处理视频播放异常的重试逻辑
- 添加单击暂停/播放、双击点赞等交互逻辑
- 如果需要禁用左右滑动能力,可调用viewPager2的
setUserInputEnabled(false)方法
内容的提问来源于stack exchange,提问作者Stan S.
相关产品推荐
相关产品推荐

