1. 程式人生 > >RecyclerView實現廣告輪播圖

RecyclerView實現廣告輪播圖

之前做的輪播圖,對於十幾個圖片什麼的能夠滿足,但是萬一有幾千張,幾萬張就容易造成記憶體洩露,使用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設定點的上內間距