RecyclerView實現廣告輪播圖
阿新 • • 發佈:2019-02-16
之前做的輪播圖,對於十幾個圖片什麼的能夠滿足,但是萬一有幾千張,幾萬張就容易造成記憶體洩露,使用RecyclerView做的輪播,可以利用它自身的複用機制,比較節省記憶體。所以這種方式感覺效果更好。
準備:build.gradle新增
compile ‘com.github.bumptech.glide:glide:3.7.0’
AndroidManifest.xml新增許可權
效果圖
public class RecyclerViewBanner extends FrameLayout {
private RecyclerView recyclerView;
private LinearLayout linearLayout;
private GradientDrawable defaultDrawable, selectedDrawable;
private ReyclerAdapter adapter;
private OnRvBannerClickListener onRvBannerClickListener;
private OnSwitchRvBannerListener onSwitchRvBannerListener;
/**
* 頁面資料
*/
private List datas = new ArrayList<>();
private int point_size, startX, startY, currentIndex;
/**
* 點的間隔
*/
private int point_padding_left,point_padding_top,point_padding_right,point_padding_bottom;
/**
* 設定是否自動播放
*/
private boolean isPlaying;
/**
* 頁面停留時間
*/
private int millisecond = 3000;
/**
* 是否顯示底部導航點
*/
private boolean isShowPoint = true;
/**
* 底部導航點的選中和未選中的顏色
*/
private int pointFocusBg, pointUnFocusBg;
private Handler handler = new Handler();
/**
* 延時切換頁面計時器
*/
private Runnable playTask = new Runnable() {
@Override
public void run() {
recyclerView.smoothScrollToPosition(++currentIndex);
if (isShowPoint) {
switchIndicatorPoint();
}
handler.postDelayed(this, millisecond);
}
};
public RecyclerViewBanner(Context context) {
this(context, null);
}
public RecyclerViewBanner(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RecyclerViewBanner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// size = (int) (5 * context.getResources().getDisplayMetrics().density + 0.5f);//dp2px預設5dp
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewBanner);
isShowPoint = typedArray.getBoolean(R.styleable.RecyclerViewBanner_isShowPoint, true);
pointFocusBg = typedArray.getColor(R.styleable.RecyclerViewBanner_pointFocusBg, 0xff0099ff);
pointUnFocusBg = typedArray.getColor(R.styleable.RecyclerViewBanner_pointUnfocusBg, 0xffffffff);
millisecond = typedArray.getInt(R.styleable.RecyclerViewBanner_interval, 3000);
point_size = typedArray.getInt(R.styleable.RecyclerViewBanner_point_size, (int) (5 * context.getResources().getDisplayMetrics().density + 0.5f));
point_padding_left = typedArray.getInt(R.styleable.RecyclerViewBanner_point_padding_left, point_size*2);
point_padding_top = typedArray.getInt(R.styleable.RecyclerViewBanner_point_padding_top, point_size*2);
point_padding_right = typedArray.getInt(R.styleable.RecyclerViewBanner_point_padding_right, point_size*2);
point_padding_bottom = typedArray.getInt(R.styleable.RecyclerViewBanner_point_padding_bottom, point_size*2);
typedArray.recycle();
recyclerView = new RecyclerView(context);
LayoutParams vpLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
linearLayout = new LinearLayout(context);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams linearLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
linearLayout.setGravity(Gravity.CENTER);
linearLayout.setPadding(point_padding_left, point_padding_top, point_padding_right, point_padding_bottom);
linearLayoutParams.gravity = Gravity.BOTTOM;
addView(recyclerView, vpLayoutParams);
addView(linearLayout, linearLayoutParams);
defaultDrawable = new GradientDrawable();
defaultDrawable.setSize(point_size, point_size);
defaultDrawable.setCornerRadius(point_size);
defaultDrawable.setColor(pointUnFocusBg);
selectedDrawable = new GradientDrawable();
selectedDrawable.setSize(point_size, point_size);
selectedDrawable.setCornerRadius(point_size);
selectedDrawable.setColor(pointFocusBg);
new PagerSnapHelper().attachToRecyclerView(recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
adapter = new ReyclerAdapter();
recyclerView.setAdapter(adapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
int first = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
int last = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
if (currentIndex != (first + last) / 2) {
currentIndex = (first + last) / 2;
if (isShowPoint) {
switchIndicatorPoint();
}
}
}
});
}
public void setPoint_size(int point_size) {
this.point_size = point_size;
}
public void setPoint_padding_left(int point_padding_left) {
this.point_padding_left = point_padding_left;
}
public void setPoint_padding_top(int point_padding_top) {
this.point_padding_top = point_padding_top;
}
public void setPoint_padding_right(int point_padding_right) {
this.point_padding_right = point_padding_right;
}
public void setPoint_padding_bottom(int point_padding_bottom) {
this.point_padding_bottom = point_padding_bottom;
}
/**
* 設定是否顯示指示器導航點
*
* @param flag
*/
public void isShowIndicatorPoint(boolean flag) {
this.isShowPoint = flag;
}
/**
* 設定輪播間隔時間
*
* @param millisecond
*/
public void setScrollIntervalTime(int millisecond) {
this.millisecond = millisecond;
}
/**
* 設定 是否自動播放(上鎖)
*
* @param playing
*/
public synchronized void setPlaying(boolean playing) {
if (!isPlaying && playing && adapter != null && adapter.getItemCount() > 2) {
handler.postDelayed(playTask, millisecond);
isPlaying = true;
} else if (isPlaying && !playing) {
handler.removeCallbacksAndMessages(null);
isPlaying = false;
}
}
/**
* 設定輪播資料集
*
* @param datas
*/
public void setRvBannerDatas(List datas) {
setPlaying(false);
this.datas.clear();
linearLayout.removeAllViews();
if (datas != null) {
this.datas.addAll(datas);
}
if (this.datas.size() > 1) {
currentIndex = this.datas.size();
adapter.notifyDataSetChanged();
recyclerView.scrollToPosition(currentIndex);
if (isShowPoint) {
for (int i = 0; i < this.datas.size(); i++) {
ImageView img = new ImageView(getContext());
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.leftMargin = point_size / 2;
lp.rightMargin = point_size / 2;
img.setImageDrawable(i == 0 ? selectedDrawable : defaultDrawable);
linearLayout.addView(img, lp);
}
}
setPlaying(true);
} else {
currentIndex = 0;
adapter.notifyDataSetChanged();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//手動觸控的時候,停止自動播放,根據手勢變換
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) ev.getX();
startY = (int) ev.getY();
getParent().requestDisallowInterceptTouchEvent(true);
setPlaying(false);
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) ev.getX();
int moveY = (int) ev.getY();
int disX = moveX - startX;
int disY = moveY - startY;
getParent().requestDisallowInterceptTouchEvent(2 * Math.abs(disX) > Math.abs(disY));
setPlaying(false);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
setPlaying(true);
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setPlaying(true);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
setPlaying(false);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
if (visibility == GONE) {
// 停止輪播
setPlaying(false);
} else if (visibility == VISIBLE) {
// 開始輪播
setPlaying(true);
}
super.onWindowVisibilityChanged(visibility);
}
/**
* recyclerview的adapter,介面卡
*/
private class ReyclerAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ImageView img = new ImageView(parent.getContext());
RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
img.setScaleType(ImageView.ScaleType.CENTER_CROP);
img.setLayoutParams(params);
img.setId(R.id.icon);
img.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onRvBannerClickListener != null) {
onRvBannerClickListener.onClick(currentIndex % datas.size());
}
}
});
return new RecyclerView.ViewHolder(img) {
};
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ImageView img = (ImageView) holder.itemView.findViewById(R.id.icon);
onSwitchRvBannerListener.switchBanner(position, img);
}
@Override
public int getItemCount() {
return datas == null ? 0 : datas.size() < 2 ? datas.size() : Integer.MAX_VALUE;
}
}
private class PagerSnapHelper extends LinearSnapHelper {
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
int targetPos = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
final View currentView = findSnapView(layoutManager);
if (targetPos != RecyclerView.NO_POSITION && currentView != null) {
int currentPostion = layoutManager.getPosition(currentView);
int first = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
int last = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
currentPostion = targetPos < currentPostion ? last : (targetPos > currentPostion ? first : currentPostion);
targetPos = targetPos < currentPostion ? currentPostion - 1 : (targetPos > currentPostion ? currentPostion + 1 : currentPostion);
}
return targetPos;
}
}
/**
* 改變導航的指示點
*/
private void switchIndicatorPoint() {
if (linearLayout != null && linearLayout.getChildCount() > 0) {
for (int i = 0; i < linearLayout.getChildCount(); i++) {
((ImageView) linearLayout.getChildAt(i)).setImageDrawable(i == currentIndex % datas.size() ? selectedDrawable : defaultDrawable);
}
}
}
/**
* 滑動切換監聽介面
*/
public interface OnSwitchRvBannerListener {
void switchBanner(int position, ImageView bannerView);
}
public void setOnSwitchRvBannerListener(OnSwitchRvBannerListener listener) {
this.onSwitchRvBannerListener = listener;
}
/**
* 點選監聽介面
*/
public interface OnRvBannerClickListener {
void onClick(int position);
}
public void setOnRvBannerClickListener(OnRvBannerClickListener onRvBannerClickListener) {
this.onRvBannerClickListener = onRvBannerClickListener;
}
}
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RecyclerViewBanner">
<attr name="pointFocusBg" format="color" />
<attr name="pointUnfocusBg" format="color" />
<attr name="interval" format="integer" />
<attr name="point_padding_left" format="integer" />
<attr name="point_padding_top" format="integer" />
<attr name="point_padding_right" format="integer" />
<attr name="point_padding_bottom" format="integer" />
<attr name="point_size" format="integer" />
<attr name="isShowPoint" format="boolean" />
</declare-styleable>
</resources>
用法:
佈局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.eno.fragment.home.FragmentMainHome">
<!-- TODO: Update blank fragment layout -->
<com.eno.widget.RecyclerViewBanner
android:id="@+id/rv_banner"
android:layout_width="match_parent"
android:layout_height="150dp"
app:interval="3000"
app:isShowPoint="true"
/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/home" />
</FrameLayout>
程式碼
public class FragmentMainHome extends BaseFragment {
@BindView(R.id.rv_banner)
RecyclerViewBanner recyclerViewBanner;
@BindView(R.id.tv_content)
TextView tvContent;
public static FragmentMainHome newInstance() {
FragmentMainHome f = new FragmentMainHome();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main_home, container, false);
ButterKnife.bind(this, view);
final List<Banner> banners = new ArrayList<>();
for (int i = 0; i < 2; i++) {
banners.add(new Banner("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487221110004&di=d6043e4b0c90ddf3ea5096c3d8eb8f58&imgtype=0&src=http%3A%2F%2Fimage.tianjimedia.com%2FuploadImages%2F2014%2F067%2F5116EPAUD762_1000x500.jpg"));
banners.add(new Banner("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487221129421&di=c085432cf7c15836f8a6479138740f39&imgtype=0&src=http%3A%2F%2Fimage85.360doc.com%2FDownloadImg%2F2015%2F05%2F0517%2F53199602_2.jpg"));
banners.add(new Banner("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487221161254&di=fbb99c5dad3d5a2a2c8b0b44e8c0e081&imgtype=0&src=http%3A%2F%2Fimage.tianjimedia.com%2FuploadImages%2F2013%2F255%2FP52AOTE73EIG_1000x500.jpg"));
}
recyclerViewBanner.isShowIndicatorPoint(true);
recyclerViewBanner.setRvBannerDatas(banners);
recyclerViewBanner.setOnSwitchRvBannerListener(new RecyclerViewBanner.OnSwitchRvBannerListener() {
@Override
public void switchBanner(int position, ImageView bannerView) {
Glide.with(bannerView.getContext()).load(banners.get(position % banners.size()).getUrl()).placeholder(R.mipmap.ic_launcher).into(bannerView);
}
});
return view;
}
@Override
public void fetchData() {
/**在這裡請求網路 */
}
private class Banner {
String url;
public Banner(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
}
}
屬性說明:
pointFocusBg 設定底部導航小圓點的選中狀態顏色
pointUnfocusBg 設定底部導航小圓點的未選中狀態顏色
interval 設定輪播圖滾動間隔時間
isShowPoint 設定是否顯示底部指示導航小圓點
point_size設定導航點的大小
point_padding_left設定點的左內間距
point_padding_right設定點的右內間距
point_padding_bottom設定點的下內間距
point_padding_top設定點的上內間距