Android使用ViewPager2實現(xiàn)簡單的輪播圖的代碼示例
一、輪播圖的簡單介紹
輪播圖(Carousel)是一種在有限空間內(nèi)循環(huán)展示多個內(nèi)容項的UI組件,用戶可以通過滑動或自動播放的方式瀏覽不同的內(nèi)容,在有限的空間中展示更多的內(nèi)容。
實現(xiàn)輪播圖主要有兩種方式,首尾添加法和取余法,這里主要講解首尾添加法的實現(xiàn)。
二、輪播圖的實現(xiàn)步驟
1.繪制輪播圖頁面
添加一個ViewPager2作為輪播圖的容器,并添加LinearLayout放置指示圖標(biāo)
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
?
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</androidx.viewpager2.widget.ViewPager2>
<LinearLayout
android:id="@+id/botttom_viewpager2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="100dp"
app:layout_constraintBottom_toBottomOf="@+id/viewpager2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="@+id/viewpager2"
>
</LinearLayout>
?
</androidx.constraintlayout.widget.ConstraintLayout>
2.設(shè)置ViewPager2的子布局
新建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">
?
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</androidx.constraintlayout.widget.ConstraintLayout>
?
3.編寫ViewPager2的適配器
因為ViewPager2實現(xiàn)基于RecyclerView,因此這里直接繼承RecyclerView.Adapter
這里我們使用Glide來加載圖片。
Glide 是一個專注于平滑滾動的 Android 圖片加載庫。
優(yōu)點:
1.使用簡單,并且支持多種圖片格式,既可以獲取網(wǎng)絡(luò)資源又可以獲取本地資源,不用處理網(wǎng)絡(luò)請求、緩存、內(nèi)存管理、圖片解碼等復(fù)雜邏輯;
2.性能優(yōu)秀:自動管理 Bitmap 內(nèi)存,防止內(nèi)存溢出,可以自動根據(jù)ImageView調(diào)整圖片大小,節(jié)省內(nèi)存。
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
private List<Integer> images;
private Context context;
public ImageAdapter(List<Integer> images){
this.images=images;
}
public int getItemCount(){
if(images!=null){
return images.size();
}
return 0;
}
public ImageViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
context=parent.getContext();
View view= LayoutInflater.from(context).inflate(R.layout.layout,parent,false);
return new ImageViewHolder(view);
}
public void onBindViewHolder(ImageViewHolder holder,int position){
Glide.with(context).load(images.get(position)).into(holder.imageView);
}
public static class ImageViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public ImageViewHolder(View view){
super(view);
imageView=view.findViewById(R.id.image);
}
}
?
4.編寫Carousel類具體實現(xiàn)輪播圖
public class Carousel {
private Context mContext;
private LinearLayout dotLinearLayout;
private List<ImageView> mImageList=new ArrayList<>();//標(biāo)志點集合
private List<Integer> originalImages=new ArrayList<>();//輪播圖圖片資源id集合
private ViewPager2 viewPager2;
public Carousel(Context mContext, LinearLayout dotLinearLayout, ViewPager2 viewPager2){
this.mContext=mContext;
this.dotLinearLayout=dotLinearLayout;
this.viewPager2=viewPager2;
}
public void initViews(int[] resourse){
//初始化輪播圖圖片資源id集合
for(int id:resourse){
originalImages.add(id);
ImageView dotImageView=new ImageView(mContext);//制作標(biāo)記點的ImageView
if(originalImages.size()==1){
dotImageView.setImageResource(R.drawable.blue_dot);//加載第一張圖片的標(biāo)志
}else {
dotImageView.setImageResource(R.drawable.grey_dot);
}
LinearLayout.LayoutParams dotImageLayoutParams=new LinearLayout.LayoutParams(60,60);
dotImageLayoutParams.setMargins(5,0,5,0);
//設(shè)置 dotImageView的布局參數(shù)
dotImageView.setLayoutParams(dotImageLayoutParams);
mImageList.add(dotImageView);
//將視圖動態(tài)添加到布局容器
dotLinearLayout.addView(dotImageView);
}
//將最后一張圖片添加到開頭,將第一張圖片添加到末尾,可以更好實現(xiàn)無限輪播的視覺效果
originalImages.add(0,originalImages.get(originalImages.size()-1));
originalImages.add(originalImages.get(1));
//設(shè)置適配器
ImageAdapter adapter=new ImageAdapter(originalImages);
viewPager2.setAdapter(adapter);
viewPager2.setCurrentItem(1,false);
//設(shè)置ViewPager2的頁面更改監(jiān)聽器,處理標(biāo)志點和邊界情況
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position){
for(int i=0;i<mImageList.size();i++){
if(i==position-1){
mImageList.get(i).setImageResource(R.drawable.blue_dot);
}else{
mImageList.get(i).setImageResource(R.drawable.grey_dot);
}
}
//滑動到最后一個元素時跳轉(zhuǎn)到第一個元素,滑動到第一個元素時跳轉(zhuǎn)到最后一個元素
if(position==originalImages.size()-1){
viewPager2.setCurrentItem(1,false);
} else if (position==0) {
viewPager2.setCurrentItem(originalImages.size()-2,false);
}
}
});
}
}
在這里簡單解釋一下取余法的實現(xiàn)原理
取余法實現(xiàn)
設(shè)置一個很大的數(shù),通過取余運算獲取真實位置,以實現(xiàn)無限循環(huán)的效果
真實數(shù)據(jù): [A, B, C] (3個元素)
虛擬位置: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... (無限)
通過取余: position % 3 = 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, ...
對應(yīng)數(shù)據(jù): A, B, C, A, B, C, A, B, C, A, ...
公式: 真實位置 = 虛擬位置 % 圖片數(shù)量
開始時從中間位置開始,保證有足夠的空間向左滑動,并且避免在邊界處出現(xiàn)問題
優(yōu)點:實現(xiàn)簡單,不需要修改數(shù)據(jù)源
缺點:雖然虛擬位置很大,但RecyclerView會回收視圖
5.實現(xiàn)自動輪播
使用Handler實現(xiàn)自動輪播效果,在初始化Carousel時同時注冊Handler
private android.os.Handler handler;
//設(shè)置是否自動播放
private boolean AUTO_SCROLL=false;
public Carousel(Context mContext, LinearLayout dotLinearLayout, ViewPager2 viewPager2){
this.mContext=mContext;
this.dotLinearLayout=dotLinearLayout;
this.viewPager2=viewPager2;
handler=new Handler(Looper.getMainLooper());
}
在Carousel中編寫控制Handler的方法
//開啟自動輪播
public void startAutoScrool(){
handler.removeCallbacks(autoScrollRunnable);//移除之前的回調(diào),防止多次啟用
handler.postDelayed(autoScrollRunnable,Banner_Time);
AUTO_SCROLL=true;
}
//在Runnable中處理自動滾動
private final Runnable autoScrollRunnable=new Runnable() {
@Override
public void run() {
int current=viewPager2.getCurrentItem();
if(current==originalImages.size()-2){
viewPager2.setCurrentItem(1,false);
} else{
viewPager2.setCurrentItem(current+1);
}
handler.postDelayed(this,Banner_Time);
}
};
public void stopAutoScrool(){
handler.removeCallbacks(autoScrollRunnable);
AUTO_SCROLL=false;
}
6.觸摸時停止自動輪播
開啟自動輪播后,用戶就無法通過滑動參看想要的頁面,因此我們還應(yīng)實現(xiàn)觸摸時停止自動輪播功能。
可以通過監(jiān)聽Viewpager2的滑動行為來實現(xiàn)觸摸時停止自動輪播。
ViewPager2中定義了三種滾動狀態(tài):
三種滾動狀態(tài)常量 // 在 ViewPager2 類中定義的常量 public static final int SCROLL_STATE_IDLE = 0; // 空閑狀態(tài),當(dāng)前沒有滾動操作,頁面完全靜止 public static final int SCROLL_STATE_DRAGGING = 1; // 拖動狀態(tài), 用戶正在用手指拖動頁面 public static final int SCROLL_STATE_SETTLING = 2; // 自動滑動狀態(tài),頁面正在自動滑動到目標(biāo)位置
我們通過對三種狀態(tài)進行分別處理來實現(xiàn)想要的效果。
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position){
for(int i=0;i<mImageList.size();i++){
if(i==position-1){
mImageList.get(i).setImageResource(R.drawable.blue_dot);
}else{
mImageList.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);
}
}
?
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
if(state==ViewPager2.SCROLL_STATE_DRAGGING){
handler.removeCallbacks(autoScrollRunnable);//在拖動時停止自動滾動
}
//在頁面靜止時
else if (state==ViewPager2.SCROLL_STATE_IDLE&&AUTO_SCROLL) {
handler.removeCallbacks(autoScrollRunnable);
handler.postDelayed(autoScrollRunnable,Banner_Time);
}
}
});
到這里我們就實現(xiàn)了簡單輪播圖的全部功能。
三、完整代碼
下面是實現(xiàn)輪播圖的完整代碼,以作參考。
public class Carousel {
private Context mContext;
private LinearLayout dotLinearLayout;
private List<ImageView> mImageList=new ArrayList<>();
private List<Integer> originalImages=new ArrayList<>();
private ViewPager2 viewPager2;
private long Banner_Time=1000;
private android.os.Handler handler;
private boolean AUTO_SCROLL=false;
public Carousel(Context mContext, LinearLayout dotLinearLayout, ViewPager2 viewPager2){
this.mContext=mContext;
this.dotLinearLayout=dotLinearLayout;
this.viewPager2=viewPager2;
handler=new Handler(Looper.getMainLooper());
}
public void initViews(int[] resourse){
for(int id:resourse){
originalImages.add(id);
ImageView dotImageView=new ImageView(mContext);
if(originalImages.size()==1){
dotImageView.setImageResource(R.drawable.blue_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);
mImageList.add(dotImageView);
dotLinearLayout.addView(dotImageView);
}
originalImages.add(0,originalImages.get(originalImages.size()-1));
originalImages.add(originalImages.get(1));
ImageAdapter adapter=new ImageAdapter(originalImages);
viewPager2.setAdapter(adapter);
viewPager2.setCurrentItem(1,false);
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position){
for(int i=0;i<mImageList.size();i++){
if(i==position-1){
mImageList.get(i).setImageResource(R.drawable.blue_dot);
}else{
mImageList.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);
}
}
?
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
if(state==ViewPager2.SCROLL_STATE_DRAGGING){
handler.removeCallbacks(autoScrollRunnable);
}
else if (state==ViewPager2.SCROLL_STATE_IDLE&&AUTO_SCROLL) {
handler.removeCallbacks(autoScrollRunnable);
handler.postDelayed(autoScrollRunnable,Banner_Time);
}
}
});
}
public void startAutoScrool(){
handler.removeCallbacks(autoScrollRunnable);
handler.postDelayed(autoScrollRunnable,Banner_Time);
AUTO_SCROLL=true;
}
private final Runnable autoScrollRunnable=new Runnable() {
@Override
public void run() {
int current=viewPager2.getCurrentItem();
if(current==originalImages.size()-2){
viewPager2.setCurrentItem(1,false);
} else{
viewPager2.setCurrentItem(current+1);
}
handler.postDelayed(this,Banner_Time);
}
};
public void stopAutoScrool(){
handler.removeCallbacks(autoScrollRunnable);
AUTO_SCROLL=false;
}
}
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
private List<Integer> images;
private Context context;
public ImageAdapter(List<Integer> images){
this.images=images;
}
public int getItemCount(){
if(images!=null){
return images.size();
}
return 0;
}
public ImageViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
context=parent.getContext();
View view= LayoutInflater.from(context).inflate(R.layout.layout,parent,false);
return new ImageViewHolder(view);
}
public void onBindViewHolder(ImageViewHolder holder,int position){
Glide.with(context).load(images.get(position)).into(holder.imageView);
}
public static class ImageViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public ImageViewHolder(View view){
super(view);
imageView=view.findViewById(R.id.image);
}
}
}
最終效果展示如下

以上就是Android使用ViewPager2實現(xiàn)簡單的輪播圖的代碼示例的詳細(xì)內(nèi)容,更多關(guān)于Android ViewPager2輪播圖的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android編程實現(xiàn)橫豎屏切換時不銷毀當(dāng)前activity和鎖定屏幕的方法
這篇文章主要介紹了Android編程實現(xiàn)橫豎屏切換時不銷毀當(dāng)前activity和鎖定屏幕的方法,涉及Android屬性設(shè)置及activity操作的相關(guān)技巧,需要的朋友可以參考下2015-11-11
Android仿微信照片選擇器實現(xiàn)預(yù)覽查看圖片
這篇文章主要介紹了Android仿微信照片選擇器實現(xiàn)預(yù)覽查看圖片的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-01-01
android實現(xiàn)主動連接和被動連接的藍(lán)牙聊天功能
這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)主動連接和被動連接的藍(lán)牙聊天功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
Android開發(fā)實現(xiàn)ListView點擊展開收起效果示例
這篇文章主要介紹了Android開發(fā)實現(xiàn)ListView點擊展開收起效果,結(jié)合實例形式分析了Android ListView控件的布局及事件響應(yīng)相關(guān)操作技巧,需要的朋友可以參考下2019-03-03

