Android Viewpager2實(shí)現(xiàn)無(wú)限輪播圖效果
ViewPager2是Android Jetpack組件的一部分,用于實(shí)現(xiàn)屏幕間平滑的水平滾動(dòng)效果。相比其前身ViewPager,ViewPager2在性能上有所提升,且支持RTL(從右到左的布局)和垂直滾動(dòng)等特性。其用法簡(jiǎn)潔,可以很容易地與RecyclerView Adapter集成,以展示大量數(shù)據(jù)集。
Android Viewpager2實(shí)現(xiàn)無(wú)限輪播圖
??先上效果圖

這就類似于常用軟件首頁(yè)的廣告輪播圖,這里只是簡(jiǎn)單顯示了幾張圖片,當(dāng)然你還可以自定義更精美的子項(xiàng)布局來(lái)實(shí)現(xiàn)想要的效果。
??使用步驟
??step1 添加依賴
首先在app/build.gradle文件中添加依賴:
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'me.relex:circleindicator:2.1.6'??step2 自定義RecyclerView.Adapter
package com.example.viewpager2test;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class CarouselAdapter extends RecyclerView.Adapter<CarouselAdapter.ViewHolder> {
private final int[] imageResources; // 圖片資源數(shù)組
public CarouselAdapter(int[] imageResources) {
this.imageResources = imageResources;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_carousel, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.imageView.setImageResource(imageResources[position]);
}
@Override
public int getItemCount() {
return imageResources.length;
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
ViewHolder(View view) {
super(view);
imageView = view.findViewById(R.id.imageView);
}
}
}其實(shí)Viewpager2的底層是基于RecyclerView實(shí)現(xiàn)的,所以用法基本上差不多,都是要自定義適配器和子項(xiàng)布局,在適配器中實(shí)現(xiàn)布局加載,控件的初始化和數(shù)據(jù)綁定等操作。
??step3 在頁(yè)面中使用
package com.example.viewpager2test;
import android.os.Bundle;
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.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager;
private LinearLayout indicatorLayout;
private BannerAdapter adapter;
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable autoScrollRunnable;
private int currentPage = 0;
private static final long AUTO_SCROLL_DELAY = 2000; // 3秒輪播間隔
private static final int INITIAL_POSITION = 1000; // 初始位置
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EdgeToEdge.enable(this);
// 初始化視圖
viewPager = findViewById(R.id.viewPager);
indicatorLayout = findViewById(R.id.indicatorLayout);
// 創(chuàng)建圖片資源列表
List<Integer> images = new ArrayList<>();
images.add(R.drawable.image1);
images.add(R.drawable.image2);
images.add(R.drawable.image3);
images.add(R.drawable.image4);
// 設(shè)置適配器
adapter = new BannerAdapter(images);
viewPager.setAdapter(adapter);
// 設(shè)置初始位置(實(shí)現(xiàn)無(wú)限循環(huán))
viewPager.setCurrentItem(INITIAL_POSITION, false);
currentPage = INITIAL_POSITION;
// 添加指示器
setupIndicators(images.size());
// 設(shè)置頁(yè)面變化監(jiān)聽(tīng)器
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
currentPage = position;
updateIndicators(position % images.size());
}
});
// 設(shè)置自動(dòng)輪播
autoScrollRunnable = new Runnable() {
@Override
public void run() {
if (currentPage == adapter.getItemCount() - 1) {
currentPage = INITIAL_POSITION;
viewPager.setCurrentItem(currentPage, false);
} else {
viewPager.setCurrentItem(++currentPage, true);
}
handler.postDelayed(this, AUTO_SCROLL_DELAY);
}
};
// 觸摸暫停功能
viewPager.setOnTouchListener((v, event) -> {
stopAutoScroll();
return false;
});
}
@Override
protected void onResume() {
super.onResume();
startAutoScroll();
}
@Override
protected void onPause() {
super.onPause();
stopAutoScroll();
}
private void setupIndicators(int count) {
indicatorLayout.removeAllViews();
for (int i = 0; i < count; i++) {
ImageView indicator = new ImageView(this);
indicator.setImageResource(i == 0 ? R.drawable.indicator_active : R.drawable.indicator_inactive);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
dpToPx(8), dpToPx(8)
);
params.setMargins(dpToPx(4), 0, dpToPx(4), 0);
indicator.setLayoutParams(params);
indicatorLayout.addView(indicator);
}
}
private void updateIndicators(int position) {
for (int i = 0; i < indicatorLayout.getChildCount(); i++) {
ImageView indicator = (ImageView) indicatorLayout.getChildAt(i);
indicator.setImageResource(i == position ?
R.drawable.indicator_active : R.drawable.indicator_inactive);
}
}
private void startAutoScroll() {
handler.postDelayed(autoScrollRunnable, AUTO_SCROLL_DELAY);
}
private void stopAutoScroll() {
handler.removeCallbacks(autoScrollRunnable);
}
private int dpToPx(int dp) {
float density = getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
// 適配器類
static class BannerAdapter extends RecyclerView.Adapter<BannerAdapter.ViewHolder> {
private final List<Integer> images;
public BannerAdapter(List<Integer> images) {
this.images = images;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_banner, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
int realPosition = position % images.size();
holder.imageView.setImageResource(images.get(realPosition));
}
@Override
public int getItemCount() {
return Integer.MAX_VALUE; // 實(shí)現(xiàn)無(wú)限循環(huán)
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
}
}
}
}關(guān)鍵點(diǎn)分析
無(wú)限循環(huán)原理
// 自動(dòng)輪播系統(tǒng)
autoScrollRunnable = new Runnable() {
@Override
public void run() {
if (currentPage == adapter.getItemCount() - 1) {
currentPage = INITIAL_POSITION;
viewPager.setCurrentItem(currentPage, false); // 無(wú)動(dòng)畫跳轉(zhuǎn)
} else {
viewPager.setCurrentItem(++currentPage, true); // 平滑滾動(dòng)
}
handler.postDelayed(this, AUTO_SCROLL_DELAY);
}
};@Override
public int getItemCount() {
return Integer.MAX_VALUE; // 實(shí)現(xiàn)無(wú)限循環(huán)
}通過(guò)設(shè)置Integer的最大值(2147483646)達(dá)到無(wú)限循環(huán)效果,同時(shí)通過(guò)setCurrentItem(INITIAL_POSITION)設(shè)定初始位置在索引等于1000的位置確保起始點(diǎn)在中間位置,每次輪播時(shí)通過(guò)position % images.size()計(jì)算實(shí)際索引獲取真實(shí)圖片位置。
??如何自定義Indicator
private void setupIndicators(int count) {
indicatorLayout.removeAllViews();
for (int i = 0; i < count; i++) {
ImageView indicator = new ImageView(this);
indicator.setImageResource(i == 0 ? R.drawable.indicator_active : R.drawable.indicator_inactive);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
dpToPx(8), dpToPx(8)
);
params.setMargins(dpToPx(4), 0, dpToPx(4), 0);
indicator.setLayoutParams(params);
indicatorLayout.addView(indicator);
}
}
private void updateIndicators(int position) {
for (int i = 0; i < indicatorLayout.getChildCount(); i++) {
ImageView indicator = (ImageView) indicatorLayout.getChildAt(i);
indicator.setImageResource(i == position ?
R.drawable.indicator_active : R.drawable.indicator_inactive);
}
}??內(nèi)置IndicatorView使用方法介紹,沒(méi)有提供任何自定義屬性
| 方法名 | 描述 |
|---|---|
| setIndicatorRadius(float indicatorRadius) | 設(shè)置圓點(diǎn)半徑 |
| setIndicatorSpacing(float indicatorSpacing) | 設(shè)置圓點(diǎn)間距 |
| setIndicatorStyle(@IndicatorStyle int indicatorStyle) | 設(shè)置圓點(diǎn)切換動(dòng)畫,內(nèi)置五種切換動(dòng)畫 |
| setIndicatorColor(@ColorInt int indicatorColor) | 設(shè)置默認(rèn)的圓點(diǎn)顏色 |
| setIndicatorSelectorColor(@ColorInt int indicatorSelectorColor) | 設(shè)置選中的圓點(diǎn)顏色 |
| setParams(RelativeLayout.LayoutParams params) | 設(shè)置IndicatorView在banner中的位置,默認(rèn)底部居中,距離底部10dp |
| setIndicatorRatio(float indicatorRatio) | 設(shè)置indicator比例,拉伸圓為矩形,設(shè)置越大,拉伸越長(zhǎng),默認(rèn)1.0 |
| setIndicatorSelectedRadius(float indicatorSelectedRadius) | 設(shè)置選中的圓角,默認(rèn)和indicatorRadius值一致,可單獨(dú)設(shè)置選中的點(diǎn)大小 |
| setIndicatorSelectedRatio(float indicatorSelectedRatio) | 設(shè)置選中圓比例,拉伸圓為矩形,控制該比例,默認(rèn)比例和indicatorRatio一致,默認(rèn)值1.0 |
| atorRatio(float indicatorRatio) | 設(shè)置indicator比例,拉伸圓為矩形,設(shè)置越大,拉伸越長(zhǎng),默認(rèn)1.0 |
| setIndicatorSelectedRadius(float indicatorSelectedRadius) | 設(shè)置選中的圓角,默認(rèn)和indicatorRadius值一致,可單獨(dú)設(shè)置選中的點(diǎn)大小 |
| setIndicatorSelectedRatio(float indicatorSelectedRatio) | 設(shè)置選中圓比例,拉伸圓為矩形,控制該比例,默認(rèn)比例和indicatorRatio一致,默認(rèn)值1.0 |
到此這篇關(guān)于Android Viewpager2實(shí)現(xiàn)無(wú)限輪播圖效果的文章就介紹到這了,更多相關(guān)Android Viewpager2輪播圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- android?ViewPager實(shí)現(xiàn)一個(gè)無(wú)限輪播圖
- Android ViewPager自定義輪播圖并解決播放沖突
- Android使用RollViewPager實(shí)現(xiàn)輪播圖
- Android Viewpager實(shí)現(xiàn)無(wú)限循環(huán)輪播圖
- Android使用viewpager實(shí)現(xiàn)自動(dòng)無(wú)限輪播圖
- Android ViewPager實(shí)現(xiàn)輪播圖效果
- Android實(shí)現(xiàn)基于ViewPager的無(wú)限循環(huán)自動(dòng)播放帶指示器的輪播圖CarouselFigureView控件
相關(guān)文章
Android自定義LinearLayout實(shí)現(xiàn)淘寶詳情頁(yè)
這篇文章主要為大家詳細(xì)介紹了Android自定義LinearLayout實(shí)現(xiàn)淘寶詳情頁(yè)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
Android如何使用圓形揭露動(dòng)畫巧妙地隱藏或顯示View詳解
Android開發(fā)中會(huì)遇到不少顯示和隱藏的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Android如何使用圓形揭露動(dòng)畫巧妙地隱藏或顯示View的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
Android ScrollView顯示到底部或任意位置實(shí)現(xiàn)代碼
這篇文章主要介紹了 Android ScrollView顯示到底部或任意位置實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02
Android中實(shí)現(xiàn)iOS中的毛玻璃效果
為了實(shí)現(xiàn)毛玻璃效果,我們需要一組compute kernels(.rs文件中編寫),及一組用于控制renderScript相關(guān)的Javaapi(.rs文件自動(dòng)生成為Java類)。 這篇文章主要介紹了Android中實(shí)現(xiàn)iOS中的毛玻璃效果,需要的朋友可以參考下2017-06-06
Android使用Handler實(shí)現(xiàn)View彈性滑動(dòng)
這篇文章主要介紹了Android使用Handler實(shí)現(xiàn)View彈性滑動(dòng),介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08
listview的上滑下滑監(jiān)聽(tīng),上下滑監(jiān)聽(tīng)隱藏頂部選項(xiàng)欄的實(shí)例
下面小編就為大家分享一篇listview的上滑下滑監(jiān)聽(tīng),上下滑監(jiān)聽(tīng)隱藏頂部選項(xiàng)欄的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
Android View 測(cè)量流程(Measure)全面解析
這篇文章主要為大家全面解析了Android View 測(cè)量流程Measure,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02

