【Android】使用ViewPager2实现轮播图效果,手动/自动轮播图

ops/2024/10/18 12:30:11/

一、轮播图的制作

1、添加Gilde依赖

这里使用Gilde进行加载图片:Glide

java">implementation 'com.github.bumptech.glide:glide:4.16.0'

使用Gilde可以加载网络图片还可以提高图片加载性能。

2、制作轮播图布局页面

java"><?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:background="#DAF3FE"tools:context=".MainActivity"tools:ignore="HardcodedText"><androidx.viewpager2.widget.ViewPager2android:id="@+id/viewPager2"android:layout_width="match_parent"android:layout_height="200dp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><LinearLayoutandroid:id="@+id/index_dot"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintBottom_toBottomOf="@+id/viewPager2"app:layout_constraintEnd_toEndOf="@+id/viewPager2"app:layout_constraintStart_toStartOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

接下来新建一个子布局item_image,加载viewPage2的子布局。

java"><?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"><ImageViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/imageView"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"/></androidx.constraintlayout.widget.ConstraintLayout>

ViewPage2就是使用recyclerView实现的,所以这里使用方法其实类似。

3、制作ViewPage2的适配器

这里直接继承RecyclerView.Adapter即可,代码很简单不必多说。

java">class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {private Context context;private List<Integer> images;public ImageAdapter(List<Integer> images) {this.images = images;}@NonNull@Overridepublic ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {context = parent.getContext();View view = LayoutInflater.from(context).inflate(R.layout.item_image, parent, false);return new ImageViewHolder(view);}@Overridepublic void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {//使用Glide加载可以优化加载流程,Glide使用异步操作Glide.with(context).load(images.get(position)).into(holder.imageView);
//        holder.imageView.setImageResource(images.get(position));}@Overridepublic int getItemCount() {return images != null ? images.size() : 0;}public static class ImageViewHolder extends RecyclerView.ViewHolder {ImageView imageView;public ImageViewHolder(@NonNull View itemView) {super(itemView);imageView = itemView.findViewById(R.id.imageView);}}
}

4、实现轮播效果

创建一个Carousel类,管理实现轮播图的方法。

java">private Context mContext;   //全局的Context用于加载图片
private LinearLayout dotLinearLayout;   //用于加载标志点的LinearLayout
private List<ImageView> mDotViewList = new ArrayList<>();//点视图集合 每个ImageView表示一个点
private  long AUTO_SCROLL_INTERVAL = 1_500; // 设置自动滚动的间隔时间,单位为毫秒public Carousel(Context mContext, LinearLayout dotLinearLayout, ViewPager2 viewPager2) {this.mContext = mContext;this.dotLinearLayout = dotLinearLayout;this.viewPager2 = viewPager2;
}public void initViews(int[] resource) {//加载初始化绑定轮播图for (int id : resource) {originalImages.add(id);//制作标志点的ImageView,并且初始化加载第一张图片标志点ImageView dotImageView = new ImageView(mContext);if (originalImages.size() == 1) {dotImageView.setImageResource(R.drawable.red_dot);} else {dotImageView.setImageResource(R.drawable.grey_dot);}//设置标志点的布局参数LinearLayout.LayoutParams dotImageLayoutParams = new LinearLayout.LayoutParams(60, 60);dotImageLayoutParams.setMargins(5, 0, 5, 0);//将布局参数绑定到标志点视图dotImageView.setLayoutParams(dotImageLayoutParams);//保存标志点便于后续动态修改mDotViewList.add(dotImageView);//将标志点的视图绑定在Layout中dotLinearLayout.addView(dotImageView);}originalImages.add(0, originalImages.get(originalImages.size() - 1));  //将originalImages的最后一张照片插入到开头originalImages.add(originalImages.get(1));  //将originalImages的第2张照片插入到结尾ImageAdapter adapter = new ImageAdapter(originalImages);viewPager2.setAdapter(adapter);// 设置当前项为数据集的第一个元素,使其显示为轮播图的开始viewPager2.setCurrentItem(1, false);// 添加页面更改监听器,以实现循环滚动viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {@Overridepublic void onPageSelected(int position) {//动态设置图片的下标点位for (int i = 0; i < mDotViewList.size(); i++) {//由于在第一张图片前添加一张过渡图,因此position比mDotViewList对于的标志点多一位if (i == position - 1) {mDotViewList.get(i).setImageResource(R.drawable.red_dot);} else {mDotViewList.get(i).setImageResource(R.drawable.grey_dot);}}// 在滑动到最后一个元素时,跳转到第一个元素if (position == originalImages.size() - 1) {viewPager2.setCurrentItem(1, false);}// 在滑动到第一个元素时,跳转到最后一个元素else if (position == 0) {viewPager2.setCurrentItem(originalImages.size() - 2, false);}}});}

initViews的参数是保存加载图片id的数组,类似于这样:

java">int[] id = {R.drawable.sys, R.drawable.sys1, R.drawable.sys2, R.drawable.sys3};

5、实现自动轮播

这里使用handler实现一个自动轮播的效果,在实现构造方法的同时实现注册Handler
设置一个全局的变量,用来判断是否设置了自动播放

private boolean AUTO_SCROLL = false; //是否设置自动播放

java">private Handler autoScrollHandler;  //控制自动轮播的线程public Carousel(Context mContext, LinearLayout dotLinearLayout, ViewPager2 viewPager2) {
this.mContext = mContext;
this.dotLinearLayout = dotLinearLayout;
this.viewPager2 = viewPager2;autoScrollHandler = new Handler(Looper.getMainLooper());
}

在Carousel类中加入以下几个方法用于管理handler

java">/*** 启动自动滚动*/
public void startAutoScroll() {autoScrollHandler.removeCallbacks(autoScrollRunnable); // 移除之前的回调,防止多次启动的情况autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_INTERVAL);AUTO_SCROLL = true;
}/*** 停止自动滚动*/
public void stopAutoScroll() {autoScrollHandler.removeCallbacks(autoScrollRunnable);AUTO_SCROLL = false;
}// 定义自动滚动的 Runnable
private final Runnable autoScrollRunnable = new Runnable() {@Overridepublic void run() {// 在这里处理自动滚动逻辑int currentItem = viewPager2.getCurrentItem();//当自动轮播到最后一张图片时,又从头开始轮播if (currentItem == originalImages.size() - 2) {viewPager2.setCurrentItem(1);} else {viewPager2.setCurrentItem(currentItem + 1);}// 重新调度下一次自动滚动autoScrollHandler.postDelayed(this, AUTO_SCROLL_INTERVAL);}
};

6、触摸暂停滚动

此时出现一个新的问题,在我们手动滑动轮播图时,handler依然控制图片移动,导致用户无法拖动的自己想看的一页。这个解决方法很简单,在ViewPage2的滑动监听事件中监听滑动行为即可。

java">@Override
public void onPageScrollStateChanged(int state) {super.onPageScrollStateChanged(state);// 当滑动开始时停止自动滚动if (state == ViewPager2.SCROLL_STATE_DRAGGING) {autoScrollHandler.removeCallbacks(autoScrollRunnable);}// 当滑动结束时重新启动自动滚动else if (state == ViewPager2.SCROLL_STATE_IDLE && AUTO_SCROLL) {autoScrollHandler.removeCallbacks(autoScrollRunnable); // 移除之前的回调,防止多次启动的情况autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_INTERVAL);}}

7、效果展示及完整代码如下:

在这里插入图片描述

代码可以直接使用,只需要重新设置几个布局文件即可:

java">import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;import com.bumptech.glide.Glide;import java.util.ArrayList;
import java.util.List;public class Carousel {private Context mContext;   //全局的Context用于加载图片private LinearLayout dotLinearLayout;   //用于加载标志点的LinearLayoutprivate List<ImageView> mDotViewList = new ArrayList<>();//点视图集合 每个ImageView表示一个点private Handler autoScrollHandler;  //控制自动轮播的线程private List<Integer> originalImages = new ArrayList<>();   //存放这需要轮播的图片private ViewPager2 viewPager2;private long AUTO_SCROLL_INTERVAL = 1_500; // 设置自动滚动的间隔时间,单位为毫秒private boolean AUTO_SCROLL = false;    //是否设置自动播放/*** @param AUTO_SCROLL_INTERVAL 设置轮播图自动滚动时间*/public void setAUTO_SCROLL_INTERVAL(long AUTO_SCROLL_INTERVAL) {this.AUTO_SCROLL_INTERVAL = AUTO_SCROLL_INTERVAL;}public Carousel(Context mContext, LinearLayout dotLinearLayout, ViewPager2 viewPager2) {this.mContext = mContext;this.dotLinearLayout = dotLinearLayout;this.viewPager2 = viewPager2;autoScrollHandler = new Handler(Looper.getMainLooper());}/*** 用于启动轮播图效果** @param resource 图片的资源ID*/public void initViews(int[] resource) {//加载初始化绑定轮播图for (int id : resource) {originalImages.add(id);//制作标志点的ImageView,并且初始化加载第一张图片标志点ImageView dotImageView = new ImageView(mContext);if (originalImages.size() == 1) {dotImageView.setImageResource(R.drawable.red_dot);} else {dotImageView.setImageResource(R.drawable.grey_dot);}//设置标志点的布局参数LinearLayout.LayoutParams dotImageLayoutParams = new LinearLayout.LayoutParams(60, 60);dotImageLayoutParams.setMargins(5, 0, 5, 0);//将布局参数绑定到标志点视图dotImageView.setLayoutParams(dotImageLayoutParams);//保存标志点便于后续动态修改mDotViewList.add(dotImageView);//将标志点的视图绑定在Layout中dotLinearLayout.addView(dotImageView);}originalImages.add(0, originalImages.get(originalImages.size() - 1));  //将originalImages的最后一张照片插入到开头originalImages.add(originalImages.get(1));  //将originalImages的第2张照片插入到结尾ImageAdapter adapter = new ImageAdapter(originalImages);viewPager2.setAdapter(adapter);// 设置当前项为数据集的第一个元素,使其显示为轮播图的开始viewPager2.setCurrentItem(1, false);// 添加页面更改监听器,以实现循环滚动viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {@Overridepublic void onPageScrollStateChanged(int state) {super.onPageScrollStateChanged(state);// 当滑动开始时停止自动滚动if (state == ViewPager2.SCROLL_STATE_DRAGGING) {autoScrollHandler.removeCallbacks(autoScrollRunnable);}// 当滑动结束时重新启动自动滚动else if (state == ViewPager2.SCROLL_STATE_IDLE && AUTO_SCROLL) {autoScrollHandler.removeCallbacks(autoScrollRunnable); // 移除之前的回调,防止多次启动的情况autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_INTERVAL);}}@Overridepublic void onPageSelected(int position) {//动态设置图片的下标点位for (int i = 0; i < mDotViewList.size(); i++) {//由于在第一张图片前添加一张过渡图,因此position比mDotViewList对于的标志点多一位if (i == position - 1) {mDotViewList.get(i).setImageResource(R.drawable.red_dot);} else {mDotViewList.get(i).setImageResource(R.drawable.grey_dot);}}// 在滑动到最后一个元素时,跳转到第一个元素if (position == originalImages.size() - 1) {viewPager2.setCurrentItem(1, false);}// 在滑动到第一个元素时,跳转到最后一个元素else if (position == 0) {viewPager2.setCurrentItem(originalImages.size() - 2, false);}}});}/*** 启动自动滚动*/public void startAutoScroll() {autoScrollHandler.removeCallbacks(autoScrollRunnable); // 移除之前的回调,防止多次启动的情况autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_INTERVAL);AUTO_SCROLL = true;}/*** 停止自动滚动*/public void stopAutoScroll() {autoScrollHandler.removeCallbacks(autoScrollRunnable);AUTO_SCROLL = false;}// 定义自动滚动的 Runnableprivate final Runnable autoScrollRunnable = new Runnable() {@Overridepublic void run() {// 在这里处理自动滚动逻辑int currentItem = viewPager2.getCurrentItem();//当自动轮播到最后一张图片时,又从头开始轮播if (currentItem == originalImages.size() - 2) {viewPager2.setCurrentItem(1);} else {viewPager2.setCurrentItem(currentItem + 1);}// 重新调度下一次自动滚动autoScrollHandler.postDelayed(this, AUTO_SCROLL_INTERVAL);}};
}class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {private Context context;private List<Integer> images;public ImageAdapter(List<Integer> images) {this.images = images;}@NonNull@Overridepublic ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {context = parent.getContext();View view = LayoutInflater.from(context).inflate(R.layout.item_image, parent, false);return new ImageViewHolder(view);}@Overridepublic void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {//使用Glide加载可以优化加载流程,Glide使用异步操作Glide.with(context).load(images.get(position)).into(holder.imageView);
//        holder.imageView.setImageResource(images.get(position));}@Overridepublic int getItemCount() {return images != null ? images.size() : 0;}public static class ImageViewHolder extends RecyclerView.ViewHolder {ImageView imageView;public ImageViewHolder(@NonNull View itemView) {super(itemView);imageView = itemView.findViewById(R.id.imageView);}}
}

http://www.ppmy.cn/ops/44303.html

相关文章

Flutter 中的 DefaultTabController 小部件:全面指南

Flutter 中的 DefaultTabController 小部件&#xff1a;全面指南 在Flutter中&#xff0c;DefaultTabController是一个用于管理Tab控制器的widget&#xff0c;它允许你控制Tab视图的初始索引和动态更新。这个组件在实现具有可滚动标签页的界面时非常有用&#xff0c;例如在设置…

AirBnb架构简史

2007 年&#xff0c;布莱恩切斯基 (Brian Chesky) 和乔加比亚 (Joe Gabbia) 搬到了旧金山。他们一边想为自己的创业想法筹集资金&#xff0c;一边又需要支付房租。 碰巧的是&#xff0c;当时城里正要举行一个设计会议&#xff0c;这意味着很多设计师都会寻找住处。他们想出了在…

pod容器基础概念

一 Pod基础概念&#xff1a; ①Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象。一个 Pod代表着集群中运行的一个进程。一个pod包含一个或多个容器。如&#xff1a;应用容器/业务容器&#xff08;淘 宝、京东、拼多多后台&#xff…

使用WebStorm如何调试Vue代码

大家好&#xff0c;我是咕噜铁蛋。今天&#xff0c;我想和大家分享一下如何使用WebStorm这款强大的IDE&#xff08;集成开发环境&#xff09;来调试Vue代码。Vue.js作为现代前端开发的利器&#xff0c;其强大的组件化开发能力和简洁的API深受开发者喜爱。然而&#xff0c;随着项…

【WEB前端2024】开源智体世界:乔布斯3D纪念馆-第28课-avatar玩家3D形象

【WEB前端2024】开源智体世界&#xff1a;乔布斯3D纪念馆-第28课-avatar玩家3D形象 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界…

ClickHouse课件

列式存储数据库&#xff1a;hbase clickhouse 简介 ClickHouse入门 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库&#xff08;DBMS&#xff09;&#xff0c;使用C语言编写&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用…

【面试题】软件测试的基础高频面试

软件测试分为几个阶段 各阶段的测试策略和要求&#xff1f; 软件测试分为以下几个阶段&#xff1a; 1. 单元测试阶段&#xff1a;测试策略注重对软件的最小代码单元进行测试&#xff0c;通常由开发人员进行。要求所有关键函数和方法都需要被测试覆盖&#xff0c;测试案例应覆…

java -- jar打包成exe -- 携带jre环境

java的项目一般都是以jar发布&#xff0c;很少打包为可执行程序&#xff0c;因此常见的打包方式也不多&#xff0c;且即使打包之后也需要jre环境才能运行&#xff0c;大部分打包都不会携带jre&#xff0c;需要手动添加jre。这里介绍几种我用过的打包方案。 exe4j(不推荐) jpac…