輪播圖
輪播圖的基本概念
定義:輪播圖是一種可以水平或垂直滑動切換的多內容展示區域,通常自動循環播放。
實現
添加依賴
這裏我們通過Glide加載圖片,所以添加Glide的依賴
implementation 'com.github.bumptech.glide:glide:4.16.0'
佈局
這裏viewpager2就是我們進行輪播的對象,LinearLayout是我們添加指示器的佈局(用於顯示當前是第幾張圖片的下標指示器);
<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/vp2_main"
android:layout_width="match_parent"
android:layout_height="400dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent">
</androidx.viewpager2.widget.ViewPager2>
<LinearLayout
android:orientation="horizontal"
android:id = "@+id/ll_main"
app:layout_constraintStart_toStartOf="@+id/vp2_main"
app:layout_constraintBottom_toBottomOf="@+id/vp2_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@+id/vp2_main">
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
為Viewpager2創建佈局
這裏很簡單,就是一個 ImageView
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id = "@+id/iv_vp2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/newyifu"
android:scaleType="centerCrop">
</ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>
Viewpager2適配器的創建
因為我們使用的是Glide加載圖片,Gilde可以大大提高圖片加載的性能,同時要異步操作;
Glide.with(context).load(list.get(position)).into(holder.imageView);
這裏with需要context,我們在onCreateViewHolder方法中可以通過父佈局來獲得context,load方法代表我們加載的資源,into代表我們要加載到哪裏;
其他部分沒變化;
public class Viewpage2Adapter extends RecyclerView.Adapter<Viewpage2Adapter.viewhold> {
List<Integer> list;
Context context;
public Viewpage2Adapter(List<Integer> list) {
this.list = list;
}
@NonNull
@Override
public viewhold onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_vp2,parent,false);
return new viewhold(view);
}
@Override
public void onBindViewHolder(@NonNull viewhold holder, int position) {
//使用glide加載可以優化流程,gilde加載屬於異步
Glide.with(context).load(list.get(position)).into(holder.imageView);
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
class viewhold extends RecyclerView.ViewHolder{
ImageView imageView;
public viewhold(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv_vp2);
}
}
}
實現輪播效果
我們通過Carousel來實現輪播效果;
public class Carousel {
private Context context;//得到context
private ViewPager2 mviewpage2;
private LinearLayout mlinearLayout;//得到它用來設置指示器
private List<ImageView> midtlist = new LinkedList<>();
private List<Integer> midlist = new LinkedList<>(); //用於存放大圖的Id,為了後續實現輪播效果
private Long AUTO_SCROLL_INTERAEL = 1_500L;
public Carousel(Context context, LinearLayout mlinearLayout, ViewPager2 mviewpage2) {
this.context = context;
this.mlinearLayout = mlinearLayout;
this.mviewpage2 = mviewpage2;
}
public void init(List<Integer> idlist) {
for (int i : idlist) {
midlist.add(i);
ImageView imageView = new ImageView(context);
if (midlist.size()==1) {
imageView.setImageResource(R.drawable.cheng);
} else {
imageView.setImageResource(R.drawable.grey);
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(50, 50);
layoutParams.setMargins(5, 0, 5, 0);
imageView.setLayoutParams(layoutParams);
midtlist.add(imageView);
mlinearLayout.addView(imageView);
}
midlist.add(0, midlist.get(midlist.size() - 1));
midlist.add(midlist.get(1));
Log.d("gk",""+midlist.get(0));
Viewpage2Adapter viewpage2Adapter = new Viewpage2Adapter(midlist);
mviewpage2.setAdapter(viewpage2Adapter);
mviewpage2.setCurrentItem(1, false);
//實現輪播
mviewpage2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
for (int i1 = 0; i1 < midtlist.size(); i1++) {
if (i1 == position - 1) {
midtlist.get(i1).setImageResource(R.drawable.cheng);
} else {
midtlist.get(i1).setImageResource(R.drawable.grey);
}
}
if (position == midlist.size() - 1) {
mviewpage2.setCurrentItem(1, false);
}
if (position == 0) {
mviewpage2.setCurrentItem(midlist.size() - 2, false);
}
super.onPageSelected(position);
}
});
}
};
}
我們來分解一下代碼:
private Context context;//得到context
private ViewPager2 mviewpage2;
private LinearLayout mlinearLayout;//得到它用來設置指示器
private List<ImageView> midtlist = new LinkedList<>();
private List<Integer> midlist = new LinkedList<>(); //用於存放大圖的Id,為了後續實現輪播效果
private Long AUTO_SCROLL_INTERAEL = 1_500L;
public Carousel(Context context, LinearLayout mlinearLayout, ViewPager2 mviewpage2) {
this.context = context;
this.mlinearLayout = mlinearLayout;
this.mviewpage2 = mviewpage2;
}
context是為了後面newImageView的對象;
mlinearLayout是為了設置指示器;
midtlist是為了後面更新指示器的操作;
因為輪播的圖片會有變動,所以我們需要保存變動後的圖片資源,記為midlist;AUTO_SCROLL_INTERAEL是輪播的時間;
for (int i : idlist) {
midlist.add(i); //把資源加到新的保存資源的List中;
ImageView imageView = new ImageView(context); //創建對應的指示器
if (midlist.size()==1) { //初始化,指向首位
imageView.setImageResource(R.drawable.cheng);
} else {
imageView.setImageResource(R.drawable.grey);
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(50, 50); //設置這個指示的寬高
layoutParams.setMargins(5, 0, 5, 0); //設置指示器的邊距
imageView.setLayoutParams(layoutParams); //綁定佈局參數
midtlist.add(imageView); //添加到list中,方便後續更新
mlinearLayout.addView(imageView); //添加到佈局中
}
這段代碼的作用是設置指示器(圖片的下標);
//把最後一張資源設置到第一張
midlist.add(0, midlist.get(midlist.size() - 1));
//把第一張資源設置到最後一張
midlist.add(midlist.get(1));
Log.d("gk",""+midlist.get(0));
Viewpage2Adapter viewpage2Adapter = new Viewpage2Adapter(midlist);
mviewpage2.setAdapter(viewpage2Adapter);
//初始化到輪播圖的第一張;
mviewpage2.setCurrentItem(1, false);
這段代碼的作用是初始化;把增加midlist的頁數就是為了輪播時的切換;比如輪播到最後一頁時,滑到下一頁就是第一頁,這是我們也偷偷切換到真的第一張,就能避免生硬的切換,使得看起來的效果更逼真;
mviewpage2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
for (int i1 = 0; i1 < midtlist.size(); i1++) {
if (i1 == position - 1) {
midtlist.get(i1).setImageResource(R.drawable.cheng);
} else {
midtlist.get(i1).setImageResource(R.drawable.grey);
}
}
if (position == midlist.size() - 1) {
mviewpage2.setCurrentItem(1, false);
}
if (position == 0) {
mviewpage2.setCurrentItem(midlist.size() - 2, false);
}
super.onPageSelected(position);
}
});
這裏的效果是手動輪播;我們自行觀看代碼理解就OK;
想解釋的一點是:i1 == position - 1這個條件,因為我們的輪播的頁面多了,但是指示器還是原來的;所以這裏我們這樣設置就能避免指示器更新混亂的問題了;
position == midlist.size() - 1就是當它是第一頁的內容的時候,我們切換為實際第一頁的內容,這樣看起來就很比較絲滑不生硬;
自動輪播
Handler handler = new Handler(Looper.getMainLooper());
//得到handler的對象
private final Runnable anToScrollRunnable = new Runnable() {
@Override
public void run() {
int currentitem = mviewpage2.getCurrentItem();
if (currentitem == midlist.size() - 2) {
mviewpage2.setCurrentItem(1,false);
} else {
mviewpage2.setCurrentItem(currentitem + 1);
}
handler.postDelayed(anToScrollRunnable, AUTO_SCROLL_INTERAEL);
}
};
這段代碼如果理解了手動的話,自動也不難理解;
然後我們在手勢變換的回調中進行設置:
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager2.SCROLL_STATE_DRAGGING) {
handler.removeCallbacks(anToScrollRunnable);
} else if (state == ViewPager2.SCROLL_STATE_IDLE) {
handler.removeCallbacks(anToScrollRunnable);
handler.postDelayed(anToScrollRunnable, AUTO_SCROLL_INTERAEL);
}
super.onPageScrollStateChanged(state);
}
handler.removeCallbacks(anToScrollRunnable); 就是在任務隊列中,移除還沒有開始執行的任務
handler.postDelayed(anToScrollRunnable, AUTO_SCROLL_INTERAEL); 就是延遲執行任務,第一個參數是任務,第二個參數是延遲的時間
那麼為什麼需要移除,因為你如果沒有取消“預約”的任務,一直堆積,那麼最後的效果可能是,1.5秒切3次等等;
handler.removeCallbacks(anToScrollRunnable);就是停止自動輪播
handler.postDelayed(anToScrollRunnable, AUTO_SCROLL_INTERAEL);就是開始自動輪播
大家可以根據自己的理解自己設置;
我實現的效果:
最後方便大家學習,貼上綜合代碼:
public class Carousel {
private Context context;//得到context
private ViewPager2 mviewpage2;
private LinearLayout mlinearLayout;//得到它用來設置指示器
private List<ImageView> midtlist = new LinkedList<>();
private List<Integer> midlist = new LinkedList<>(); //用於存放大圖的Id,為了後續實現輪播效果
private boolean AUTO_SCROLL = false;
private Long AUTO_SCROLL_INTERAEL = 1_500L;
Handler handler = new Handler(Looper.getMainLooper());
public Carousel(Context context, LinearLayout mlinearLayout, ViewPager2 mviewpage2) {
this.context = context;
this.mlinearLayout = mlinearLayout;
this.mviewpage2 = mviewpage2;
}
public void init(List<Integer> idlist) {
for (int i : idlist) {
midlist.add(i);
ImageView imageView = new ImageView(context);
if (midlist.size()==1) {
imageView.setImageResource(R.drawable.cheng);
} else {
imageView.setImageResource(R.drawable.grey);
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(50, 50);
layoutParams.setMargins(5, 0, 5, 0);
imageView.setLayoutParams(layoutParams);
midtlist.add(imageView);
mlinearLayout.addView(imageView);
}
midlist.add(0, midlist.get(midlist.size() - 1));
midlist.add(midlist.get(1));
Log.d("gk",""+midlist.get(0));
Viewpage2Adapter viewpage2Adapter = new Viewpage2Adapter(midlist);
mviewpage2.setAdapter(viewpage2Adapter);
mviewpage2.setCurrentItem(1, false);
//實現輪播
mviewpage2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager2.SCROLL_STATE_DRAGGING) {
handler.removeCallbacks(anToScrollRunnable);
} else if (state == ViewPager2.SCROLL_STATE_IDLE) {
handler.removeCallbacks(anToScrollRunnable);
handler.postDelayed(anToScrollRunnable, AUTO_SCROLL_INTERAEL);
}
super.onPageScrollStateChanged(state);
}
@Override
public void onPageSelected(int position) {
for (int i1 = 0; i1 < midtlist.size(); i1++) {
if (i1 == position - 1) {
midtlist.get(i1).setImageResource(R.drawable.cheng);
} else {
midtlist.get(i1).setImageResource(R.drawable.grey);
}
}
if (position == midlist.size() - 1) {
mviewpage2.setCurrentItem(1, false);
}
if (position == 0) {
mviewpage2.setCurrentItem(midlist.size() - 2, false);
}
super.onPageSelected(position);
}
});
}
private final Runnable anToScrollRunnable = new Runnable() {
@Override
public void run() {
int currentitem = mviewpage2.getCurrentItem();
if (currentitem == midlist.size() - 2) {
mviewpage2.setCurrentItem(1,false);
} else {
mviewpage2.setCurrentItem(currentitem + 1);
}
handler.postDelayed(anToScrollRunnable, AUTO_SCROLL_INTERAEL);
}
};
}
public class Viewpage2Adapter extends RecyclerView.Adapter<Viewpage2Adapter.viewhold> {
List<Integer> list;
Context context;
public Viewpage2Adapter(List<Integer> list) {
this.list = list;
}
@NonNull
@Override
public viewhold onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_vp2,parent,false);
return new viewhold(view);
}
@Override
public void onBindViewHolder(@NonNull viewhold holder, int position) {
//使用glide加載可以優化流程,gilde加載屬於異步
Glide.with(context).load(list.get(position)).into(holder.imageView);
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
class viewhold extends RecyclerView.ViewHolder{
ImageView imageView;
public viewhold(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv_vp2);
}
}
}