ViewPager实现左右无限循环

项目中ViewPager来展示推广栏,要实现ViewPager的左右无限翻页,在网上找了好几个开源例子,实现方式有两种,一种是基于getCount()方法返回Integer.MAX_VALUE实现的伪无限,另一种是在ViewPager的展示数据中,头尾各增加一个数据项,实现左右循环。

下面BannerView就是笔者根据自己的需求和参考网友的,实现推广栏的左右无限循环滑动,原理是基于:ViewPager的展示数据中,头尾各增加一个数据项,实现左右循环。
package com.leenanxi.open;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

/**
 * Created by ngudream on 16-9-28.
 */
public class AccountBannerView extends RelativeLayout {
    private static final int DEFAULT_INTERVAL_TIME = 5 * 1000;

//    private static final int titleBackgroundColor = Color.parseColor("#ffffff");

    private Context mContext;
    private int mIntervalTime = DEFAULT_INTERVAL_TIME;

    private boolean isLoopable = true;
    private boolean isTitleEnabled = true;
    private ViewPager mViewPager = null;
    private LinearLayout mBottomLayout = null;

    private TextView mTextView = null;

    private List<View> mIndicatorViews = null;

    private BannerViewAdapter mBannerAdapter = null;

    private int mCurrentPosition = -1;
    private boolean mPageChanged = false;
    private PageControlBar mPagerControlBar;
    private Subscription mLoopSub;

    @Override
    protected void onDetachedFromWindow() {
        stopAutoScroll();
        super.onDetachedFromWindow();
    }

    public AccountBannerView(Context context) {
        super(context);
        initialize(context, null);
    }

    public AccountBannerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(context, attrs);
    }

    public AccountBannerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public AccountBannerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initialize(context, attrs);
    }

    public void setTitleEnabled(boolean enable) {
        if (enable) {
//            mBottomLayout.setBackgroundColor(titleBackgroundColor);
            mTextView.setVisibility(View.VISIBLE);
        } else {
            mBottomLayout.setBackgroundColor(Color.TRANSPARENT);
            mTextView.setVisibility(View.GONE);
        }
    }

    private void initialize(Context context, AttributeSet attrs) {
        this.mContext = context;
        mViewPager = new ViewPager(context);
        mViewPager.setClipChildren(false);
        mViewPager.setPageMargin(50);
        mViewPager.setOffscreenPageLimit(3);
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                mPageChanged = mCurrentPosition != position;
                mCurrentPosition = position;
                if(mBannerAdapter.getRealDataCount() < mBannerAdapter.getCount()) {
                    if(0 == position) {
                        mPagerControlBar.setLastPage();
                    } else if(mBannerAdapter.getCount() - 1 == position) {
                        mPagerControlBar.setFirstPage();
                    } else {
                        mPagerControlBar.setCurrentPage(mViewPager.getCurrentItem() - 1);
                    }
                } else {
                    mPagerControlBar.setCurrentPage(mViewPager.getCurrentItem());
                }
                startAutoScroll();
            }

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                if(ViewPager.SCROLL_STATE_IDLE == state) {
                    if(mPageChanged && mBannerAdapter.getRealDataCount() < mBannerAdapter.getCount()) {
                        if(0 == mCurrentPosition) {
                            mViewPager.setCurrentItem(mBannerAdapter.getCount() - 2, false);
                        } else if(mBannerAdapter.getCount() - 1 == mCurrentPosition) {
                            mViewPager.setCurrentItem(1, false);
                        }
                    }
                    mPageChanged = false;
                    startAutoScroll();
                } else {
                    stopAutoScroll();
                }
            }
        });
        addView(mViewPager, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mBottomLayout = new LinearLayout(context);
        LayoutParams bottomParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        bottomParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        mBottomLayout.setLayoutParams(bottomParams);
//        mBottomLayout.setBackgroundColor(titleBackgroundColor);
        int bottomPadding = dip2px(context, 5);
        mBottomLayout.setPadding(bottomPadding, bottomPadding, bottomPadding, bottomPadding);
        mBottomLayout.setOrientation(LinearLayout.VERTICAL);
        mBottomLayout.setGravity(android.view.Gravity.CENTER);

        mTextView = new TextView(context);
        LayoutParams textLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        mTextView.setLayoutParams(textLayoutParams);
        mTextView.setTextColor(Color.WHITE);
        mTextView.setGravity(View.TEXT_ALIGNMENT_CENTER);
        mBottomLayout.addView(mTextView);

        mPagerControlBar = new PageControlBar(context);
        LayoutParams indicatorLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        mPagerControlBar.setPadding(0, dip2px(context, 2), 0, 0);
        mPagerControlBar.setLayoutParams(indicatorLayoutParams);
        mBottomLayout.addView(mPagerControlBar);
        addView(mBottomLayout);

        mIndicatorViews = new ArrayList<>();
    }

    public void setOnItemClickListener(OnItemClickListener l) {
        mBannerAdapter.setOnItemClickListener(l);
    }

    public boolean isLoopable() {
        return isLoopable;
    }

    /**
     * 是否自动循环
     * @param loopable
     */
    public void setLoopable(boolean loopable) {
        isLoopable = loopable;
    }

    public void addBannerItems(List<BannerItem> items, boolean notifyDataSetChanged) {
        if (items == null || items.size() == 0) {
            Log.e("TAG", "banner data is empty!");
            return;
        }

        if (mBannerAdapter == null) {
            mBannerAdapter = new BannerViewAdapter(items);
            mViewPager.setAdapter(mBannerAdapter);
            if(items.size() > 1){
                mViewPager.setCurrentItem(1, false);
            }
        } else {
            mBannerAdapter.addBannerItems(items, notifyDataSetChanged);
        }
        mPagerControlBar.setPageCount(mBannerAdapter.getRealDataCount());
        mPagerControlBar.setFirstPage();
    }

    /**
     * 设置当前页<br/><br/>
     * 为了实现循环滑动,在数据的最前端和最后端分别添加了最后一个数据和第一个数据,用这个方法设置当前显示,
     * 会自动转换成原来数据的下标。
     * @param item
     * @param smoothScroll
     */
    public void setCurrentItem(int item, boolean smoothScroll) {
        if(mBannerAdapter.getRealDataCount() < 1) {
            return;
        }
        try {
            if(mBannerAdapter.getRealDataCount() < mBannerAdapter.getCount()) {
                if(item < 1) {
                    mViewPager.setCurrentItem(1, smoothScroll);
                } else if(item > mBannerAdapter.getCount() - 2) {
                    mViewPager.setCurrentItem(mBannerAdapter.getCount() - 2, smoothScroll);
                } else {
                    mViewPager.setCurrentItem(item + 1, smoothScroll);
                }
            } else {
                mViewPager.setCurrentItem(item, smoothScroll);
            }
        } catch (Exception e) {
            Log.e("BannerView", "setCurrentItem error", e);
        }
    }

    //获取下一个需要显示的banner的位置
    private int getNextItemPosition(int currentItem) {
        if (currentItem + 1 == mBannerAdapter.getCount()) {
            return 0;
        } else {
            return currentItem + 1;
        }
    }

    /**
     * 设置轮播时间间隔
     *
     * @param mIntervalTime
     */
    public void setIntervalTime(int mIntervalTime) {
        this.mIntervalTime = mIntervalTime;
    }

    /**
     * 开始自动切换
     */
    private void startAutoScroll() {
        if(isLoopable) {
            if (mLoopSub == null) {
                createLoop();
            } else if (!mLoopSub.isUnsubscribed()) {
                mLoopSub.unsubscribe();
                createLoop();
            }
        }
    }

    private void createLoop(){
        mLoopSub = Observable.interval(mIntervalTime, TimeUnit.SECONDS, Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        setCurrentItem(mPagerControlBar.getCurrentPage() + 1, true);
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        Log.d("test", throwable.getMessage());
                    }
                });
    }

    /**
     * 停止自动切换
     */
    private void stopAutoScroll() {
        if(mLoopSub != null) {
            mLoopSub.unsubscribe();
            mLoopSub = null;
        }
    }

    public void onDestroy(){
        if(mLoopSub != null){
            mLoopSub.unsubscribe();
            mLoopSub = null;
        }
    }

    private int dip2px(Context context, float dpValue) {
        if (context == null) return 0;
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public void setImageLoadder(ImageLoader imageLoader) {
        mBannerAdapter.setImageLoadder(imageLoader);
    }

    public interface OnItemClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param position The position that was clicked.
         */
        void onClick(int position);
    }

    public interface ImageLoader {
        void loadImage(ImageView imageView, String url);
    }


    public static class BannerItem {
        private String title;
        private String url;

        public BannerItem(String title, String url) {
            this.title = title;
            this.url = url;
        }

        public String getTitle() {
            return title;
        }

        public String getUrl() {
            return url;
        }

        public BannerItem clone(){
            BannerItem item = new BannerItem(title, url);
            return item;
        }
    }

    //adapter
    public class BannerViewAdapter extends RecyclingPagerAdapter {
        public OnItemClickListener mOnItemClickListener;
        private List<BannerItem> mBannerItems;
        private int mBannerCount;
        private ImageLoader mImageLoader;

        public BannerViewAdapter(List<BannerItem> items) {
            initItemList(items);
            mBannerCount = mBannerItems.size();
        }

        public void setBannerItems(List<BannerItem> items) {
            initItemList(items);
            mBannerCount = items.size();
        }

        public void setOnItemClickListener(OnItemClickListener l) {
            mOnItemClickListener = l;
        }

        @Override
        public int getCount() {
            return mBannerCount;
            Integer.MAX_VALUE
        }

        private BannerItem getItem(int position) {
            return mBannerItems.get(getPosition(position));
        }

        public int getPosition(int position){
            return position % mBannerCount;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup container) {
            // TODO Auto-generated method stub
            final ViewHolder holder;
            final BannerItem item = getItem(position);
            if (convertView == null) {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(container.getContext()).inflate(R.layout.account_banner, container, false);
                holder.mImageView = (ImageView)convertView.findViewById(R.id.iv_banner);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            if (mImageLoader != null) {
                mImageLoader.loadImage(holder.mImageView, item.getUrl());
            }
            holder.mImageView.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                }
            });
            return convertView;
        }

        public void initItemList(List<BannerItem> items) {
            List<BannerItem> newMediaList = new ArrayList<>();
            newMediaList.addAll(items);
            if (newMediaList.size() > 1) {
                //第0个位最后一个,向左拉动时,可以实现直接滑动到最后一个,最后一个是第0个,可以实现向右滑动的时直接跳到第0个
                newMediaList.add(0, items.get(items.size() - 1));
                newMediaList.add(items.get(0));
            }
            mBannerItems = newMediaList;
        }

        public void setImageLoadder(ImageLoader imageLoader) {
            this.mImageLoader = imageLoader;
        }

        private class ViewHolder {
            ImageView mImageView = null;
        }

        /**
         * 获取真实的position
         * @return
         */
        public int getRealDataCount() {
            if(mBannerItems.size() < 2) {
                return mBannerItems.size();
            }
            return mBannerItems.size() - 2;
        }

        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }

        public void addBannerItems(List<BannerItem> items, boolean notifyDataSetChanged) {
            if(null == items || items.isEmpty()) {
                return;
            }
            if(mBannerItems.size() > 3) {
                mBannerItems.remove(0);
                mBannerItems.remove(mBannerItems.size() - 1);
            }
            mBannerItems.addAll(items);
            if(items.size() > 1) {
                mBannerItems.add(0, mBannerItems.get(mBannerItems.size() -1).clone());
                mBannerItems.add(mBannerItems.get(1).clone());
            }
            if(notifyDataSetChanged) {
                notifyDataSetChanged();
            }
        }
    }
}

底部的控件条就是PageControlBar实现的:

ublic class PageControlBar extends LinearLayout {

	private Context mContext;
    private RadioGroup mRadioGroup;
    private int mCurrentPage = -1;

	public PageControlBar(Context context) {
		super(context);
		init(context);
	}

	public PageControlBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	private void init(Context context) {
		mContext = context;
		setOrientation(HORIZONTAL);
		setGravity(Gravity.CENTER);

        mRadioGroup = new RadioGroup(context);
        mRadioGroup.setOrientation(HORIZONTAL);
        mRadioGroup.setGravity(Gravity.CENTER);

        addView(mRadioGroup);
	}

    private RadioButton newRadioButton(Context context) {
        RadioButton radioButton = new RadioButton(context);
        radioButton.setButtonDrawable(R.drawable.selector_page_indicator);
        radioButton.setPadding(5, 0, 5, 0);
        return radioButton;
    }

    /**
     * 设置页数
     * @param count
     */
	public void setPageCount(int count) {
        int currentCount = mRadioGroup.getChildCount();
        if(count > currentCount) {
            for(int i = 0; i < count - currentCount; i++) {
                mRadioGroup.addView(newRadioButton(mContext));
            }
        } else if(count < currentCount) {
            mRadioGroup.removeViews(count, currentCount - count);
        }
	}

    /**
     * 获取当前指示页面
     * @return
     */
    public int getCurrentPage() {
        return mCurrentPage;
    }

    /**
     * 设置当前页
     * @param currentItem
     */
	public void setCurrentPage(int currentItem) {
        if(mRadioGroup.getChildCount() == 0 || currentItem < 0) {
            return;
        }
        mCurrentPage = currentItem % mRadioGroup.getChildCount();
        RadioButton radioButton = (RadioButton) mRadioGroup.getChildAt(mCurrentPage);
        radioButton.setChecked(true);
	}

    /**
     * 指示器显示第一页
     */
    public void setFirstPage() {
        if(mRadioGroup.getChildCount() < 1) {
            return;
        }
        setCurrentPage(0);
    }

    /**
     * 指示器显示最后一页
     */
    public void setLastPage() {
        if(mRadioGroup.getChildCount() < 1) {
            return;
        }
        setCurrentPage(mRadioGroup.getChildCount() - 1);
    }
}

其中PagerAdapter是继续自JakeWharton大神的RecyclingPagerAdapter,这样要实现的adapter的方法就和实现普通(ListView)的一样,View的回收由RecycleBin处理。

RecyclingPagerAdapter:

/**
 * A {@link PagerAdapter} which behaves like an {@link android.widget.Adapter} with view types and
 * view recycling.
 */
public abstract class RecyclingPagerAdapter extends PagerAdapter {
    static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;

    private final RecycleBin recycleBin;

    public RecyclingPagerAdapter() {
        this(new RecycleBin());
    }

    RecyclingPagerAdapter(RecycleBin recycleBin) {
        this.recycleBin = recycleBin;
        recycleBin.setViewTypeCount(getViewTypeCount());
    }

    @Override
    public void notifyDataSetChanged() {
        recycleBin.scrapActiveViews();
        super.notifyDataSetChanged();
    }

    @Override
    public final Object instantiateItem(ViewGroup container, int position) {
        int viewType = getItemViewType(position);
        View view = null;
        if (viewType != IGNORE_ITEM_VIEW_TYPE) {
            view = recycleBin.getScrapView(position, viewType);
        }
        view = getView(position, view, container);
        container.addView(view);
        return view;
    }

    @Override
    public final void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
        container.removeView(view);
        int viewType = getItemViewType(position);
        if (viewType != IGNORE_ITEM_VIEW_TYPE) {
            recycleBin.addScrapView(view, position, viewType);
        }
    }

    @Override
    public final boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    /**
     * <p>
     * Returns the number of types of Views that will be created by
     * {@link #getView}. Each type represents a set of views that can be
     * converted in {@link #getView}. If the adapter always returns the same
     * type of View for all items, this method should return 1.
     * </p>
     * <p>
     * This method will only be called when when the adapter is set on the
     * the {@link AdapterView}.
     * </p>
     *
     * @return The number of types of Views that will be created by this adapter
     */
    public int getViewTypeCount() {
        return 1;
    }

    /**
     * Get the type of View that will be created by {@link #getView} for the specified item.
     *
     * @param position The position of the item within the adapter's data set whose view type we
     *                 want.
     * @return An integer representing the type of View. Two views should share the same type if one
     * can be converted to the other in {@link #getView}. Note: Integers must be in the
     * range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can
     * also be returned.
     * @see #IGNORE_ITEM_VIEW_TYPE
     */
    @SuppressWarnings("UnusedParameters") // Argument potentially used by subclasses.
    public int getItemViewType(int position) {
        return 0;
    }

    /**
     * Get a View that displays the data at the specified position in the data set. You can either
     * create a View manually or inflate it from an XML layout file. When the View is inflated, the
     * parent View (GridView, ListView...) will apply default layout parameters unless you use
     * {@link android.view.LayoutInflater#inflate(int, ViewGroup, boolean)}
     * to specify a root view and to prevent attachment to the root.
     *
     * @param position    The position of the item within the adapter's data set of the item whose view
     *                    we want.
     * @param convertView The old view to reuse, if possible. Note: You should check that this view
     *                    is non-null and of an appropriate type before using. If it is not possible to convert
     *                    this view to display the correct data, this method can create a new view.
     *                    Heterogeneous lists can specify their number of view types, so that this View is
     *                    always of the right type (see {@link #getViewTypeCount()} and
     *                    {@link #getItemViewType(int)}).
     * @param parent      The parent that this view will eventually be attached to
     * @return A View corresponding to the data at the specified position.
     */
    public abstract View getView(int position, View convertView, ViewGroup container);

}

RecycleBin:

/**
 * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
 * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
 * start of a layout. By construction, they are displaying current information. At the end of
 * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
 * could potentially be used by the adapter to avoid allocating views unnecessarily.
 * <p/>
 * This class was taken from Android's implementation of {@link android.widget.AbsListView} which
 * is copyrighted 2006 The Android Open Source Project.
 */
public class RecycleBin {
    /**
     * Views that were on screen at the start of layout. This array is populated at the start of
     * layout, and at the end of layout all view in activeViews are moved to scrapViews.
     * Views in activeViews represent a contiguous range of Views, with position of the first
     * view store in mFirstActivePosition.
     */
    private View[] activeViews = new View[0];
    private int[] activeViewTypes = new int[0];

    /**
     * Unsorted views that can be used by the adapter as a convert view.
     */
    private SparseArray<View>[] scrapViews;

    private int viewTypeCount;

    private SparseArray<View> currentScrapViews;

    public void setViewTypeCount(int viewTypeCount) {
        if (viewTypeCount < 1) {
            throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
        }
        //noinspection unchecked
        SparseArray<View>[] scrapViews = new SparseArray[viewTypeCount];
        for (int i = 0; i < viewTypeCount; i++) {
            scrapViews[i] = new SparseArray<View>();
        }
        this.viewTypeCount = viewTypeCount;
        currentScrapViews = scrapViews[0];
        this.scrapViews = scrapViews;
    }

    protected boolean shouldRecycleViewType(int viewType) {
        return viewType >= 0;
    }

    /**
     * @return A view from the ScrapViews collection. These are unordered.
     */
    View getScrapView(int position, int viewType) {
        if (viewTypeCount == 1) {
            return retrieveFromScrap(currentScrapViews, position);
        } else if (viewType >= 0 && viewType < scrapViews.length) {
            return retrieveFromScrap(scrapViews[viewType], position);
        }
        return null;
    }

    /**
     * Put a view into the ScrapViews list. These views are unordered.
     *
     * @param scrap The view to add
     */
    void addScrapView(View scrap, int position, int viewType) {
        if (viewTypeCount == 1) {
            currentScrapViews.put(position, scrap);
        } else {
            scrapViews[viewType].put(position, scrap);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            scrap.setAccessibilityDelegate(null);
        }
    }

    /**
     * Move all views remaining in activeViews to scrapViews.
     */
    void scrapActiveViews() {
        final View[] activeViews = this.activeViews;
        final int[] activeViewTypes = this.activeViewTypes;
        final boolean multipleScraps = viewTypeCount > 1;

        SparseArray<View> scrapViews = currentScrapViews;
        final int count = activeViews.length;
        for (int i = count - 1; i >= 0; i--) {
            final View victim = activeViews[i];
            if (victim != null) {
                int whichScrap = activeViewTypes[i];

                activeViews[i] = null;
                activeViewTypes[i] = -1;

                if (!shouldRecycleViewType(whichScrap)) {
                    continue;
                }

                if (multipleScraps) {
                    scrapViews = this.scrapViews[whichScrap];
                }
                scrapViews.put(i, victim);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    victim.setAccessibilityDelegate(null);
                }
            }
        }

        pruneScrapViews();
    }

    /**
     * Makes sure that the size of scrapViews does not exceed the size of activeViews.
     * (This can happen if an adapter does not recycle its views).
     */
    private void pruneScrapViews() {
        final int maxViews = activeViews.length;
        final int viewTypeCount = this.viewTypeCount;
        final SparseArray<View>[] scrapViews = this.scrapViews;
        for (int i = 0; i < viewTypeCount; ++i) {
            final SparseArray<View> scrapPile = scrapViews[i];
            int size = scrapPile.size();
            final int extras = size - maxViews;
            size--;
            for (int j = 0; j < extras; j++) {
                scrapPile.remove(scrapPile.keyAt(size--));
            }
        }
    }

    static View retrieveFromScrap(SparseArray<View> scrapViews, int position) {
        int size = scrapViews.size();
        if (size > 0) {
            // See if we still have a view for this position.
            for (int i = 0; i < size; i++) {
                int fromPosition = scrapViews.keyAt(i);
                View view = scrapViews.get(fromPosition);
                if (fromPosition == position) {
                    scrapViews.remove(fromPosition);
                    return view;
                }
            }
            int index = size - 1;
            View r = scrapViews.valueAt(index);
            scrapViews.remove(scrapViews.keyAt(index));
            return r;
        } else {
            return null;
        }
    }
}

RecyclingPagerAdapter的github地址:https://github.com/JakeWharton/salvage

文章目录
|