RecyclerView廣告輪播有兩個難點,首先是無限循環,網上很多修改Adapter的有缺陷,自定義一個LayoutManager無疑是一個好選擇;難點二:每次隻滾動一頁,這個就需要自定義PagerSnapHelper,并且LayoutManager需要implements RecyclerView.SmoothScroller.ScrollVectorProvider
如果你是新手可以看看這篇文章,講解很詳細
https://blog.csdn.net/ww897532167/article/details/86585214
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<android.support.v7.widget.RecyclerView
android:id="@+id/advertisingCarousel"
android:layout_width="match_parent"
android:layout_height="200dp"/>
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="150dp"
android:orientation="horizontal">
</RadioGroup>
</RelativeLayout>
item布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
初始化
List<SmartDrinkBean> list = new ArrayList<>();
list.add(new SmartDrinkBean(R.drawable.image_sz));
list.add(new SmartDrinkBean(R.drawable.image_sz));
list.add(new SmartDrinkBean(R.drawable.image_sz));
list.add(new SmartDrinkBean(R.drawable.image_sz));
RadioButtons = new ArrayList<>();
for (int i=0;i< list.size();i++) {
RadioButton radioButton = new RadioButton(mContext);
radioGroup.addView(radioButton);
RadioButtons.add(radioButton);
}
SmartDrinkAdapter smartDrinkAdapter = new SmartDrinkAdapter(R.layout.item_smart_drink,list);
layoutManager = new AdvertisingCarouselLayoutManager(mContext);
advertisingCarousel.setLayoutManager(layoutManager);
advertisingCarousel.setAdapter(smartDrinkAdapter);
//像ViewPager一樣的效果,一次隻能滑一頁,而且居中顯示。
ViewPagerSnapHelper snapHelper = new ViewPagerSnapHelper();
snapHelper.attachToRecyclerView(advertisingCarousel);
int position = layoutManager.getLayoutPosition();
RadioButtons.get(position).setChecked(true);
advertisingCarousel.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE ){
int position = layoutManager.getLayoutPosition();
RadioButtons.get(position).setChecked(true);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
自定義LayoutManager
public class AdvertisingCarouselLayoutManager extends RecyclerView.LayoutManager implements RecyclerView.SmoothScroller.ScrollVectorProvider {
private Context context;
//目前item的位置
private int layoutPosition = 0;
public AdvertisingCarouselLayoutManager(Context context){
this.context = context;
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
/**
* 擷取目前item的Position
* @return
*/
public int getLayoutPosition(){
return layoutPosition;
}
public void setLayoutPosition(int layoutPosition){
this.layoutPosition = layoutPosition;
}
/**
* 繪制初始化item
* @param recycler
* @param state
*/
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
//分離并且回收目前附加的所有View
detachAndScrapAttachedViews(recycler);
if (getItemCount() == 0) {
return;
}
//橫向繪制子View,則需要知道 X軸的偏移量
int offsetX = 0;
//繪制并添加view
for (int i = 0; i < getItemCount(); i++) {
View view = recycler.getViewForPosition(i);
addView(view);
measureChildWithMargins(view, 0, 0);
int viewWidth = getDecoratedMeasuredWidth(view);
int viewHeight = getDecoratedMeasuredHeight(view);
layoutDecorated(view, offsetX, 0, offsetX + viewWidth, viewHeight);
offsetX += viewWidth;
//超出RecyclerView範圍則不繪制子View
if (offsetX > getWidth()){
break;
}
}
}
/**
* 是否可橫向滑動
* @return
*/
@Override
public boolean canScrollHorizontally() {
return true;
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
recycleViews(dx, recycler);
fill(dx,recycler);
/**
* 橫向移動所有子View
* 為什麼要 * -1 ? 螢幕xy軸原點在左上角,左移則需要View的坐标 x - offset 右移則需要 x + offset
* 是以需要 dx * -1
*/
offsetChildrenHorizontal(dx * -1);
return dx;
}
/**
* 橫向清單循環
*
* @param dx
* @param recycler
*/
private void fill(int dx, RecyclerView.Recycler recycler) {
//左滑
if (dx > 0) {
while (true) {
//得到目前已添加(可見)的最後一個子View
View lastVisibleView = getChildAt(getChildCount() - 1);
if (lastVisibleView == null) {
break;
}
//如果滑動過後,View還是未完全顯示出來就 不進行繪制下一個View
if (lastVisibleView.getRight() - dx > getWidth()) {
break;
}
//得到View對應的位置
layoutPosition = getPosition(lastVisibleView);
View newView;
//getItemCount()-1 最後一個item的位置
if (layoutPosition == getItemCount() - 1) {
newView = recycler.getViewForPosition(0);
} else {
newView = recycler.getViewForPosition(layoutPosition + 1);
}
//添加一個新view
addView(newView);
measureChildWithMargins(newView, 0, 0);
//擷取新view的大小
int viewWidth = getDecoratedMeasuredWidth(newView);
int viewHeight = getDecoratedMeasuredHeight(newView);
//最後一個可見view的右邊距
int offsetX = lastVisibleView.getRight();
layoutDecorated(newView, offsetX, 0, offsetX + viewWidth, viewHeight);
}
} else { //右滑
while (true) {
View firstVisibleView = getChildAt(0);
if (firstVisibleView == null) {
break;
}
if (firstVisibleView.getLeft() - dx < 0) break;
//得到View對應的位置
layoutPosition = getPosition(firstVisibleView);
View newView;
//如果目前第一個可見View為第0個,則左側顯示最後一個View ,如果不是,下一個就顯示前一個
if (layoutPosition == 0) {
newView = recycler.getViewForPosition(getItemCount() - 1);
} else {
newView = recycler.getViewForPosition(layoutPosition - 1);
}
//第一個可見位置添加一個新view
addView(newView, 0);
measureChildWithMargins(newView, 0, 0);
//擷取新view的大小
int viewWidth = getDecoratedMeasuredWidth(newView);
int viewHeight = getDecoratedMeasuredHeight(newView);
//第一個可見view的右邊距
int offsetX = firstVisibleView.getLeft();
layoutDecorated(newView, offsetX - viewWidth, 0, offsetX, viewHeight);
}
}
}
/**
* 回收view
* @param dx
* @param recycler
*/
private void recycleViews(int dx, RecyclerView.Recycler recycler){
for (int i = 0;i < getItemCount() ; i++){
//擷取可見item
View view = getChildAt(i);
if (view == null) return;
//左滑
if (dx > 0) {
//移除并回收 原點 左側的子View
if (view.getRight() - dx < 0) {
removeAndRecycleViewAt(i, recycler);
}
} else { //右滑
//移除并回收 右側即RecyclerView寬度之以外的子View
if (view.getLeft() - dx > getWidth()) {
removeAndRecycleViewAt(i, recycler);
}
}
}
}
/**
* 像ViewPager一樣的效果,一次隻能滑一頁,而且居中顯示。
* @param targetPosition
* @return
*/
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
if (getChildCount() == 0) {
return null;
}
int firstChildPos = getPosition(getChildAt(0));
int direction;
if (targetPosition < firstChildPos) {
direction = -1;
} else {
direction = 1;
}
return new PointF(direction, 0);
}
}
自定義PagerSnapHelper
public class ViewPagerSnapHelper extends PagerSnapHelper{
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
int position = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
if (position >= layoutManager.getItemCount()) {
return 0;
}
return super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
}
}
擴充卡
public class SmartDrinkAdapter extends BaseRecyclerViewAdapter<SmartDrinkBean,BaseViewHolder>{
public SmartDrinkAdapter(@LayoutRes int resource, @Nullable List<SmartDrinkBean> data) {
super(resource, data);
}
@Override
public void convert(@NonNull BaseViewHolder holder, SmartDrinkBean item, int position) {
holder.setImageView(R.id.imageView,item.getImage());
}
}
循環滾動
在AdvertisingCarouselLayoutManager中重寫smoothScrollToPosition方法
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext());
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
開啟線程調用以下代碼便可以實作循環滾動
int position = layoutManager.getLayoutPosition();
if (position == smartDrinkAdapter.data.size() - 1){
position = 0;
}else {
position = position + 1;
}
advertisingCarousel.smoothScrollToPosition(position);
RadioButtons.get(position).setChecked(true);
layoutManager.setLayoutPosition(position);