如何優雅的實現一個可復用的 PagerAdapter

這幾天在項目中需要用到輪播圖,由于不想使用別人開源的,于是直接使用了 ViewPager 來實現了,ViewPager 實現輪播圖這里就不贅述了

開始的時候是直接繼承的 PagerAdapter

public class BannerAdapter extends PagerAdapter {
    private Context mContext;
    private List<BannerBean> mDataList;

    public BannerAdapter(Context context) {
        this.mContext = context;
    }

    public void setDataList(List<BannerBean> dataList) {
        this.mDataList = dataList;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        final BannerBean bean = mDataList.get(position % mDataList.size());
        View rootView = View.inflate(mContext, R.layout.xxx, null);
        container.addView(rootView);
        return rootView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

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

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

很簡單,在 getCount() 函數里,返回 Integer.MAX_VALUE ,其他函數正常寫即可
但是這樣會存在一個問題,在 ViewPager 不停的滾動的時候,就會不停的調用 instantiateItem() 函數,這就會導致不停的 inflate 新的 View,這樣是十分不好的
首先想到的就是 itemView 復用,當然,實現復用也是很簡單的,看下面

// 緩存 list
private LinkedList<View> mViewCache = new LinkedList<>();

@Override
public Object instantiateItem(ViewGroup container, int position) {
    View convertView = null;
    if (mViewCache.size() == 0) {
        convertView = mLayoutInflater.inflate(R.layout.xxx, null, false);
    } else {
        convertView = mViewCache.removeFirst();
    }
    container.addView(convertView);
    return convertView;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    View contentView = (View) object;
    container.removeView(contentView);
    mViewCache.add(contentView);
}

OK 功能實現了,等等,說好的優雅 呢?你 ?逗我?

找屎.jpg

為了更優雅的實現,我可是加(huó)班(gāi)半個多小時,連寫帶自測才搞定

Talk is cheap. Show me the code

/**
 * 仿照 recyclerview.adapter 實現的具有 item view 復用功能的 PagerAdapter
 */
public abstract class ReusePagerAdapter<VH extends ReusePagerAdapter.Holder> extends PagerAdapter {

    private SparseArray<LinkedList<VH>> holders = new SparseArray<>(1);

    /**
     * 獲取 item count
     *
     * @return count
     */
    public abstract int getItemCount();

    /**
     * 獲取 view type
     *
     * @param position position
     * @return type
     */
    public int getItemViewType(int position) {
        return 0;
    }

    /**
     * 創建 holder
     *
     * @param parent   parent
     * @param viewType type
     * @return holder
     */
    public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);

    /**
     * 綁定 holder
     *
     * @param holder   holder
     * @param position position
     */
    public abstract void onBindViewHolder(VH holder, int position);

    @Override
    public int getCount() {
        return getItemCount();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // 獲取 position 對應的 type
        int itemViewType = getItemViewType(position);
        // 根據 type 找到緩存的 list
        LinkedList<VH> holderList = holders.get(itemViewType);
        VH holder;
        if (holderList == null) {
            // 如果 list 為空,表示沒有緩存
            // 調用 onCreateViewHolder 創建一個 holder
            holder = onCreateViewHolder(container, itemViewType);
            holder.itemView.setTag(R.id.holder_id, holder);
        } else {
            holder = holderList.pollLast();
            if (holder == null) {
                // 如果 list size = 0,表示沒有緩存
                // 調用 onCreateViewHolder 創建一個 holder
                holder = onCreateViewHolder(container, itemViewType);
                holder.itemView.setTag(R.id.holder_id, holder);
            }
        }
        holder.position = position;
        holder.viewType = itemViewType;
        // 調用 onBindViewHolder 對 itemView 填充數據
        onBindViewHolder(holder, position);
        container.addView(holder.itemView);
        return holder.itemView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
        container.removeView(view);
        VH holder = (VH) view.getTag(R.id.holder_id);
        int itemViewType = holder.viewType;
        LinkedList<VH> holderList = holders.get(itemViewType);
        if (holderList == null) {
            holderList = new LinkedList<>();
            holders.append(itemViewType, holderList);
        }
        // 緩存 holder
        holderList.push(holder);
    }

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

    public static abstract class Holder {
        public View itemView;
        public int viewType;
        public int position;

        public Holder(View view) {
            if (view == null) {
                throw new IllegalArgumentException("itemView may not be null");
            }
            itemView = view;
        }
    }
}

holder 要保存在 itemView 的 tag 中,為了防止沖突,需要指定一個 id

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="holder_id" type="id" />
</resources>

子類在繼承 ReusePagerAdapter 的時候,可以直接像寫 RecyclerView 的 Adapter 那樣寫就可以了

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容