RecyclerView 添加頭部 尾部 中間插入View 底部監(jiān)聽

以前寫過一篇關(guān)于RecyclerView的頭部尾部的添加
也有一個(gè)Demo 不過Linear Grid Stagge三個(gè)是分開的 如下圖1 今天的是一個(gè)整合的DRecyclerView 如下圖二 講一下實(shí)現(xiàn)過程

以前的分開的

這是整合的 使用更加方便


現(xiàn)在的整合的

先看效果圖

1.gif
  • 首先來分析最簡(jiǎn)單的 也就是LinearLayoutManager情況下的 添加頭部 尾部 和中間插入
    在繼承RecyclerView的使用中 兩個(gè)關(guān)鍵方法
    onCreateViewHolder 和 onBindViewHolder
    onCreateViewHolder 創(chuàng)建布局View
    onBindViewHolder 綁定數(shù)據(jù)
    所以我們要在顯示不同的布局上做處理 就只能在 onCreateViewHolder 創(chuàng)建的時(shí)候做處理
    觀察 onCreateViewHolder 這個(gè)方法 通過該方法參數(shù)
    onCreateViewHolder(ViewGroup parent, int viewType) {---}
    發(fā)現(xiàn) 我們能做處理的 只有viewType 這個(gè)字段 看字面意思也能猜到是不同view的類型
    然后我們看源碼
Paste_Image.png
Paste_Image.png

然后 getItemType(int position) 這個(gè)方法上面說了 用來返回不同的View的type 也就是說 onCreateViewHolder中的ViewType來自這個(gè)方法 默認(rèn)是返回0 我們?cè)谧约旱奶幚碇兄貙戇@個(gè)方法就行了

我們就返回 當(dāng)前進(jìn)來的position

Paste_Image.png

然后在onCreateViewHolder中自己處理

好 現(xiàn)在在分析 整個(gè)類 要具備的一些條件
一個(gè)HeadViews 的集合 緩存所有的HeadView
一個(gè)FootViews的集合 緩存所有的FootView
一個(gè)中間插入的View的 集合 緩存所有的插入View[這個(gè)View就是數(shù)據(jù)列表中不同的類型做不同的布局 一般滑動(dòng)很多顯示一個(gè) 推薦 等等]

整個(gè)DRecyclerViewAdapater 代碼如下

public class DRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final String Tag = DRecyclerViewAdapter.class.getName();
private RecyclerView.Adapter mInnerAdapter;
public DRecyclerViewAdapter(DBaseRecyclerViewAdapter adapter) {
    setAdapter(adapter);
}
public void setAdapter(DBaseRecyclerViewAdapter myAdapter) {
    if (myAdapter != null) {
        if (!(myAdapter instanceof RecyclerView.Adapter))
            throw new RuntimeException("your adapter must be a RecyclerView.Adapter");
    }
    this.mInnerAdapter = myAdapter;
    myAdapter.setDRecyclerViewAdapter(this);
}

/**
 * head foot list cache
 */
private List<View> mHeadViews = new ArrayList<View>();
private List<View> mFootViews = new ArrayList<View>();
private List<View> mRandomViews = new ArrayList<View>();
private SparseArray<Integer> mRandomViews_position = new SparseArray<Integer>();

/**
 * addHead to recyclerview
 *
 * @param view
 */
public void addHeadView(View view) {
    mHeadViews.add(view);
}

/**
 * addFoot to RecyclerView
 *
 * @param view
 */
public void addFootView(View view) {
    mFootViews.add(view);
}

/**
 * 使用一次 存下來 后續(xù) 好查找
 */
private int index=0;
public void addRandomView(View view, int posistion) {
    mRandomViews_position.append(posistion,index);
    index++;
    mRandomViews.add(view);
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    DRecyclerViewHolder dRecyclerViewHolder;
    Log.e(Tag, "當(dāng)前type " + viewType);
    if (viewType < mHeadViews.size()) {
        Log.e(Tag, "headView" + viewType);
        return new DRecyclerViewHolder(mHeadViews.get(viewType));

    } else if (viewType >= mHeadViews.size() && viewType < mHeadViews.size() + mInnerAdapter.getItemCount()) {

        if (mRandomViews_position.get(viewType - mHeadViews.size())!=null) {
            View view = mRandomViews.get(mRandomViews_position.get(viewType - mHeadViews.size()));
            return new DRecyclerViewHolder(view);
        }
        return mInnerAdapter.onCreateViewHolder(parent, viewType - mHeadViews.size());
    } else {
        Log.e(Tag, "FootView" + viewType);
        int position = viewType - mHeadViews.size() - mInnerAdapter.getItemCount();
        if (position >= 0 && position < mFootViews.size()) {
            return new DRecyclerViewHolder(mFootViews.get(position));
        } else {
            return null;
        }
    }
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (position >= mHeadViews.size() && position < mHeadViews.size() + mInnerAdapter.getItemCount()) {
        //不包括那些插入的
        if (mRandomViews_position.get(position - mHeadViews.size())==null)
            mInnerAdapter.onBindViewHolder(holder, position - mHeadViews.size());

    } else {
        /**
         * 瀑布流的設(shè)置處理
         */
        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
        if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
            ((StaggeredGridLayoutManager.LayoutParams) layoutParams).setFullSpan(true);
        }
    }
}

@Override
public int getItemCount() {
    return mHeadViews.size() + mInnerAdapter.getItemCount() + mFootViews.size();
}

@Override
public int getItemViewType(int position) {

    return position;
}

public int getFootSize() {
    return mFootViews.size();
}

public int getHeadSize() {
    return mHeadViews.size();
}

public boolean isHeader(int position) {
    return position < mHeadViews.size() ? true : false;
}

public boolean isFooter(int position) {
    return position >= mHeadViews.size() + mInnerAdapter.getItemCount() ? true : false;
}

public boolean isRandom(int position){
    Log.e("isRandom",position+"  "+mRandomViews_position.get(position-mHeadViews.size()));
    return mRandomViews_position.get(position-mHeadViews.size())!=null?true:false;
}

static class DRecyclerViewHolder extends RecyclerView.ViewHolder {

    public DRecyclerViewHolder(View itemView) {
        super(itemView);
    }
}
}

可以看到 邏輯處理在onCreateViewHolder中
根據(jù)進(jìn)來的ViewType 也就是position
整套羅不難 就是根據(jù)position的位置來區(qū)分來區(qū)分屬于哪個(gè)地方的View
mRandomViews_position 這個(gè)是處理中間數(shù)據(jù)不同的記錄 用的SparseArray 類似Map 效率高些 節(jié)約內(nèi)存 查找內(nèi)部二分查找 不多介紹
目的是 記錄 列表數(shù)據(jù)中的 那些位置是插入的 不同的View

上面是LinearLayoutManager的情況 屬于最簡(jiǎn)單的情況

分析一下GridLayoutManager 這個(gè) 主要方法就是 這個(gè)方法 源碼里面有

Paste_Image.png

設(shè)置每個(gè)Item 所占得位置 默認(rèn)是1 如果你的2列 這里可以在添加頭部的時(shí)候 設(shè)置為2 就會(huì)占一整行了

所以 封裝一個(gè) 類 繼承GridLayoutManager.SpanSizeLookup 是頭部 尾部 插入位置 都占用一個(gè)大格

  /**
   * Created by Daemon on 2015/11/10.
   */
  public class DSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {

private DRecyclerViewAdapter adapter;
private int mSpanSize = 1;

public DSpanSizeLookup(DRecyclerViewAdapter adapter, int spanSize) {
    this.adapter = adapter;
    this.mSpanSize = spanSize;
}

@Override
public int getSpanSize(int position) {
    boolean isHeaderOrFooterOrRandom = adapter.isHeader(position) || adapter.isFooter(position)
    || adapter.isRandom(position);
    return isHeaderOrFooterOrRandom ? mSpanSize : 1;
}
}

所以在使用的時(shí)候 設(shè)置這個(gè)就行了 其余的不變

在看看 StaggeredGridLayoutManager 這里就要用到

  LayoutParams lp = (LayoutParams)   
  view.getLayoutParams();lp.setFullSpan(true);

這種方法 來設(shè)置 不同的占用列數(shù) 重寫onMeasure方法 處理

Paste_Image.png

這樣就是整個(gè)的使用原理
至于其中的DBaseRecyclerViewAdapter DBaseRecyclerViewHolder 等等都是一些輔助類 更加方便使用 和添加頭部 尾部 沒得啥具體關(guān)系 不介紹了

MainActivity的使用代碼

  public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private DRecyclerViewAdapter dRecyclerViewAdapter;
private LinearLayoutManager linearLayoutManager;
private Button bt_linear;
private Button bt_grid;
private Button bt_stagge;
private MyAdpater myAdpater;
private GridLayoutManager gridLayoutManager;

private DStaggeredGridLayoutManager staggeLayoutManager;

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.bt_linear:

            if (linearLayoutManager == null) {
                linearLayoutManager = new LinearLayoutManager(MainActivity.this);
            }
            rcv_list.setLayoutManager(linearLayoutManager);
            dRecyclerViewAdapter.notifyDataSetChanged();

            rcv_list.addOnScrollListener(new DRecyclerViewScrollListener() {
                @Override
                public void onLoadNextPage(RecyclerView view) {
                    Toast.makeText(MainActivity.this,"底部",Toast.LENGTH_SHORT).show();
                }
            });

            break;

        case R.id.bt_grid:

            if (gridLayoutManager == null) {
                gridLayoutManager = new GridLayoutManager(MainActivity.this, 2);
                gridLayoutManager.setSpanSizeLookup(new DSpanSizeLookup(dRecyclerViewAdapter, gridLayoutManager.getSpanCount()));
            }
            rcv_list.setLayoutManager(gridLayoutManager);
            dRecyclerViewAdapter.notifyDataSetChanged();
            rcv_list.addOnScrollListener(new DRecyclerViewScrollListener() {
                @Override
                public void onLoadNextPage(RecyclerView view) {
                    Toast.makeText(MainActivity.this,"底部",Toast.LENGTH_SHORT).show();
                }
            });

            break;

        case R.id.bt_stagge:

            Intent intent=new Intent(MainActivity.this,Main2Activity.class);

            startActivity(intent);

            break;

    }
}

private RecyclerView rcv_list;
private List<Data> list;

public static class Data{
    public String value;
    public int type;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    rcv_list = (RecyclerView) findViewById(R.id.rcv_list);

    bt_linear = (Button) findViewById(R.id.bt_linear);
    bt_grid = (Button) findViewById(R.id.bt_grid);
    bt_stagge = (Button) findViewById(R.id.bt_stagge);

    list = new ArrayList<Data>();

    bt_linear.setOnClickListener(this);
    bt_grid.setOnClickListener(this);
    bt_stagge.setOnClickListener(this);
    for (int i = 0; i < 20; i++) {
        Data data=new Data();
        data.value="Daemon data " + i;
        data.type=0;

        list.add(data);
        //一種判斷標(biāo)示 可以根據(jù)實(shí)際需求來做標(biāo)識(shí)
        if (i % 5 == 0) {
             data.type=1;
        }
    }

    myAdpater = new MyAdpater(list, this);
    dRecyclerViewAdapter = new DRecyclerViewAdapter(myAdpater);

    linearLayoutManager = new LinearLayoutManager(MainActivity.this);

    rcv_list.setLayoutManager(linearLayoutManager);

    addHeadViews();
    addFootviews();
    addRandomView();

    myAdpater.setOnClickItemListsner(new DBaseRecyclerViewAdapter.OnClickItemListsner() {
        @Override
        public void onClick(int poisiton) {
            Toast.makeText(MainActivity.this, poisiton + "", Toast.LENGTH_SHORT).show();
        }
    });

    rcv_list.setAdapter(dRecyclerViewAdapter);

    rcv_list.addOnScrollListener(new DRecyclerViewScrollListener() {
        @Override
        public void onLoadNextPage(RecyclerView view) {
            Toast.makeText(MainActivity.this,"底部",Toast.LENGTH_SHORT).show();
        }
    });
}

/**
 * 添加全部的Views 中間插入的廣告欄 等等
 */
private void addRandomView() {
    for(int i=0 ; i<list.size();i++){
        if(list.get(i).type==1){
            View view = LayoutInflater.from(this).inflate(R.layout.random_item, rcv_list, false);
            dRecyclerViewAdapter.addRandomView(view,i);
        }
    }
}

/**
 * add HeadView
 */
private void addHeadViews() {
    View head = LayoutInflater.from(this).inflate(R.layout.head, rcv_list, false);
    View head1 = LayoutInflater.from(this).inflate(R.layout.head, rcv_list, false);
    dRecyclerViewAdapter.addHeadView(head);
    dRecyclerViewAdapter.addHeadView(head1);

}

/**
 * add Footview
 */
private void addFootviews() {
    View foot = LayoutInflater.from(this).inflate(R.layout.foot, rcv_list, false);
    View foot1 = LayoutInflater.from(this).inflate(R.layout.foot, rcv_list, false);

    dRecyclerViewAdapter.addFootView(foot);
    dRecyclerViewAdapter.addFootView(foot1);
}

/**
 * 繼承封裝過的DBaseRecyclerViewAdapter
 */
 class MyAdpater extends DBaseRecyclerViewAdapter<Data> {

    public MyAdpater(List<Data> mDatas, Context mContext) {
        super(mDatas, mContext);
    }

    @Override
    protected DBaseRecyclerViewHolder onCreateViewHolder1(ViewGroup parent, int viewType) {
        return new MyViewHoder(parent, R.layout.item, this);
    }

}

/**
 * 繼承封裝過的 DBaseRecyclerViewHolder
 */
class MyViewHoder extends DBaseRecyclerViewHolder<Data> implements View.OnClickListener {

    private TextView tv_content;

    public MyViewHoder(ViewGroup parent, @LayoutRes int res, DBaseRecyclerViewAdapter dBaseRecyclerViewAdapter) {
        super(parent, res, dBaseRecyclerViewAdapter);
        tv_content = $(R.id.tv_content);

        itemView.setOnClickListener(this);
    }

    @Override
    public void setData(Data data, int position) {

        //每次默認(rèn)初始化 因?yàn)镾tagge會(huì)改變高度
        ViewGroup.LayoutParams layoutParams1 = tv_content.getLayoutParams();
        layoutParams1.height = 80;
        tv_content.setLayoutParams(layoutParams1);

        tv_content.setText(data.value);
    }

    @Override
    public void onClick(View v) {
        if (getOnClickItemListsner() != null) {
            getOnClickItemListsner().onClick(getAdapterItemPosition());
        }
    }
}
}

放在Github上面 整個(gè)Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容