Android高级UI开发 RecyclerView高级进阶(六)偷梁换柱之 添加头部和尾部
众所周知Listview控件可以通过addHeaderView和addFooterView来添加头部和尾部,但是我们的 RecyclerView控件却没有这样的 API,那我们就得自己扩展这样的API到RecyclerView控件里。既然Listview已经实现了这样的API,我们不防看看ANDROID listview源码,我们可以模仿它。
效果图:
原理图:
一、分析listview源码
1. Listview源码片段1: Listview.addHeaderView(...)
添加头部
-
/**
-
* Add a fixed view to appear at the top of the list. If this method is
-
* called more than once, the views will appear in the order they were
-
* added. Views added using this call can take focus if they want.
-
* <p>
-
* Note: When first introduced, this method could only be called before
-
* setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
-
* {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
-
* called at any time. If the ListView's adapter does not extend
-
* {@link HeaderViewListAdapter}, it will be wrapped with a supporting
-
* instance of {@link WrapperListAdapter}.
-
*
-
* @param v The view to add.
-
* @param data Data to associate with this view
-
* @param isSelectable whether the item is selectable
-
*/
-
public void addHeaderView(View v, Object data, boolean isSelectable) {
-
if (v.getParent() != null && v.getParent() != this) {
-
if (Log.isLoggable(TAG, Log.WARN)) {
-
Log.w(TAG, "The specified child already has a parent. "
-
+ "You must call removeView() on the child's parent first.");
-
}
-
}
-
final FixedViewInfo info = new FixedViewInfo();
-
info.view = v;
-
info.data = data;
-
info.isSelectable = isSelectable;
-
mHeaderViewInfos.add(info);
-
mAreAllItemsSelectable &= isSelectable;
-
-
// Wrap the adapter if it wasn't already wrapped.
-
if (mAdapter != null) {
-
if (!(mAdapter instanceof HeaderViewListAdapter)) {
-
wrapHeaderListAdapterInternal();
-
}
-
-
// In the case of re-adding a header view, or adding one later on,
-
// we need to notify the observer.
-
if (mDataSetObserver != null) {
-
mDataSetObserver.onChanged();
-
}
-
}
-
}
-
protected void wrapHeaderListAdapterInternal() {
-
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
-
}
-
protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
-
ArrayList<ListView.FixedViewInfo> headerViewInfos,
-
ArrayList<ListView.FixedViewInfo> footerViewInfos,
-
ListAdapter adapter) {
-
return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);
-
}
我们来分析以上 listview中添加头部的API 源码,主要看红色部分,
(1)mHeaderViewInfos.add(info)
意图是在数组mHeaderViewInfos里添加头部信息info中的vie w就是我们添加的头部布局,info.data就是 为header准备数据,info.isSelectable定义头部是否可以选择,这个一般用于TV上的光标选择。既然mHeaderViewInfos是一个数组,说明Listview可以添加多个头部。总结一下,就是mHeaderViewInfos可以添加多个 头部view。
(2)wrapHeaderListAdapterInternal函数
从上述代码中可以看出 该函数最终调用了
return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter)
也就是说返回了一个全新的adapter = HeaderViewListAdapter, 观察3个构造函数参分别是头部视图、尾部视图,普通adapter.看 来这个全新的adapter不一般,它可以处理带 有头部和尾部视图以及正常条目的ListView 。总结一下,就是当listview有头部和尾部的时候,会专门为这样的listview重新封装一个HeaderViewListAdapter,这个HeaderViewListAdapter会为listview显示不同类型的布局,如头部布局、正常条目的布局、尾部布局。
2. Listview源码片段2 setAdapter函数
-
/**
-
* Sets the data behind this ListView.
-
*
-
* The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
-
* depending on the ListView features currently in use. For instance, adding
-
* headers and/or footers will cause the adapter to be wrapped.
-
*
-
* @param adapter The ListAdapter which is responsible for maintaining the
-
* data backing this list and for producing a view to represent an
-
* item in that data set.
-
*
-
* @see #getAdapter()
-
*/
-
@Override
-
public void setAdapter(ListAdapter adapter) {
-
if (mAdapter != null && mDataSetObserver != null) {
-
mAdapter.unregisterDataSetObserver(mDataSetObserver);
-
}
-
-
resetList();
-
mRecycler.clear();
-
-
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
-
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
-
} else {
-
mAdapter = adapter;
-
}
-
-
mOldSelectedPosition = INVALID_POSITION;
-
mOldSelectedRowId = INVALID_ROW_ID;
-
-
// AbsListView#setAdapter will update choice mode states.
-
super.setAdapter(adapter);
-
-
if (mAdapter != null) {
-
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
-
mOldItemCount = mItemCount;
-
mItemCount = mAdapter.getCount();
-
checkFocus();
-
-
mDataSetObserver = new AdapterDataSetObserver();
-
mAdapter.registerDataSetObserver(mDataSetObserver);
-
-
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
-
-
int position;
-
if (mStackFromBottom) {
-
position = lookForSelectablePosition(mItemCount - 1, false);
-
} else {
-
position = lookForSelectablePosition(0, true);
-
}
-
setSelectedPositionInt(position);
-
setNextSelectedPositionInt(position);
-
-
if (mItemCount == 0) {
-
// Nothing selected
-
checkSelectionChanged();
-
}
-
} else {
-
mAreAllItemsSelectable = true;
-
checkFocus();
-
// Nothing selected
-
checkSelectionChanged();
-
}
-
-
requestLayout();
-
}
以上是Listview的setAdapter函数
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0)
表面当有头部或尾部的时候
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
mAdapter实质被赋值为一个封装过的adapter,与源码片段1一样,封装过的adapter就是HeaderViewListAdapter。
也就是说,我们通常表面上调用的是setAdapter(adapter),实质当我们调用了addHeaderView函数之后,系统会帮我们把正常条目的adapter做了一次全新的封装,封装后的HeaderViewListAdapter有能力去显示头部、尾部,正常条目的。
二、模仿(一)中的Listview的源码来扩展RecyclerView(可添加头部与尾部)
1.我们要扩展RecyclerView,那自然先创建一个子类继承RecyclerView
-
package com.anyikang.volunteer.sos.recyclerview;
-
-
import android.content.Context;
-
import android.support.v7.widget.RecyclerView;
-
import android.util.AttributeSet;
-
import android.view.View;
-
-
import java.util.ArrayList;
-
-
public class MyRecyclerView extends RecyclerView{
-
private ArrayList<View> mHeaderViewInfos = new ArrayList<View>();
-
private ArrayList<View> mFooterViewInfos = new ArrayList<View>();
-
private Adapter mAdapter;
-
-
public MyRecyclerView(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
}
-
-
public void addHeaderView(View v) {
-
mHeaderViewInfos.add(v);
-
-
// Wrap the adapter if it wasn't already wrapped.
-
if (mAdapter != null) {
-
if (!(mAdapter instanceof HeaderViewAdapterForRecycler )) {
-
mAdapter = new HeaderViewAdapterForRecycler (mHeaderViewInfos, mFooterViewInfos, mAdapter);
-
}
-
}
-
}
-
-
public void addFooterView(View v) {
-
mFooterViewInfos.add(v);
-
-
// Wrap the adapter if it wasn't already wrapped.
-
if (mAdapter != null) {
-
if (!(mAdapter instanceof HeaderViewAdapterForRecycler )) {
-
mAdapter = new HeaderViewAdapterForRecycler (mHeaderViewInfos, mFooterViewInfos, mAdapter);
-
}
-
}
-
}
-
-
@Override
-
public void setAdapter(Adapter adapter) {
-
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
-
mAdapter = new HeaderViewAdapterForRecycler (mHeaderViewInfos, mFooterViewInfos, adapter);
-
} else {
-
mAdapter = adapter;
-
}
-
super.setAdapter(mAdapter);
-
}
-
-
}
是否有种似曾相识的感觉。继承于RecyclerView主要扩展了3个函数:addHeaderView增加头部、addFooterView增加尾部、重写了setAdapter. 这3个函数都干了同一件事:那就是如果我们添加了头部(尾部),我们的adapter将偷梁换柱成HeaderViewAdapterForRecycler,可显示头、中、尾条目的适配器。现在是时候来分析这个顶梁柱HeaderViewAdapterForRecycler的时候了。
三、老套路,先分析Listview中的HeaderViewListAdapter的源码
-
/*
-
* Copyright (C) 2006 The Android Open Source Project
-
*
-
* Licensed under the Apache License, Version 2.0 (the "License");
-
* you may not use this file except in compliance with the License.
-
* You may obtain a copy of the License at
-
*
-
* http://www.apache.org/licenses/LICENSE-2.0
-
*
-
* Unless required by applicable law or agreed to in writing, software
-
* distributed under the License is distributed on an "AS IS" BASIS,
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-
* See the License for the specific language governing permissions and
-
* limitations under the License.
-
*/
-
-
package android.widget;
-
-
import android.database.DataSetObserver;
-
import android.view.View;
-
import android.view.ViewGroup;
-
-
import java.util.ArrayList;
-
-
/**
-
* ListAdapter used when a ListView has header views. This ListAdapter
-
* wraps another one and also keeps track of the header views and their
-
* associated data objects.
-
*<p>This is intended as a base class; you will probably not need to
-
* use this class directly in your own code.
-
*/
-
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {
-
-
private final ListAdapter mAdapter;
-
-
// These two ArrayList are assumed to NOT be null.
-
// They are indeed created when declared in ListView and then shared.
-
ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
-
ArrayList<ListView.FixedViewInfo> mFooterViewInfos;
-
-
// Used as a placeholder in case the provided info views are indeed null.
-
// Currently only used by some CTS tests, which may be removed.
-
static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST =
-
new ArrayList<ListView.FixedViewInfo>();
-
-
boolean mAreAllFixedViewsSelectable;
-
-
private final boolean mIsFilterable;
-
-
public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
-
ArrayList<ListView.FixedViewInfo> footerViewInfos,
-
ListAdapter adapter) {
-
mAdapter = adapter;
-
mIsFilterable = adapter instanceof Filterable;
-
-
if (headerViewInfos == null) {
-
mHeaderViewInfos = EMPTY_INFO_LIST;
-
} else {
-
mHeaderViewInfos = headerViewInfos;
-
}
-
-
if (footerViewInfos == null) {
-
mFooterViewInfos = EMPTY_INFO_LIST;
-
} else {
-
mFooterViewInfos = footerViewInfos;
-
}
-
-
mAreAllFixedViewsSelectable =
-
areAllListInfosSelectable(mHeaderViewInfos)
-
&& areAllListInfosSelectable(mFooterViewInfos);
-
}
-
-
public int getHeadersCount() {
-
return mHeaderViewInfos.size();
-
}
-
-
public int getFootersCount() {
-
return mFooterViewInfos.size();
-
}
-
-
public boolean isEmpty() {
-
return mAdapter == null || mAdapter.isEmpty();
-
}
-
-
private boolean areAllListInfosSelectable(ArrayList<ListView.FixedViewInfo> infos) {
-
if (infos != null) {
-
for (ListView.FixedViewInfo info : infos) {
-
if (!info.isSelectable) {
-
return false;
-
}
-
}
-
}
-
return true;
-
}
-
-
public boolean removeHeader(View v) {
-
for (int i = 0; i < mHeaderViewInfos.size(); i++) {
-
ListView.FixedViewInfo info = mHeaderViewInfos.get(i);
-
if (info.view == v) {
-
mHeaderViewInfos.remove(i);
-
-
mAreAllFixedViewsSelectable =
-
areAllListInfosSelectable(mHeaderViewInfos)
-
&& areAllListInfosSelectable(mFooterViewInfos);
-
-
return true;
-
}
-
}
-
-
return false;
-
}
-
-
public boolean removeFooter(View v) {
-
for (int i = 0; i < mFooterViewInfos.size(); i++) {
-
ListView.FixedViewInfo info = mFooterViewInfos.get(i);
-
if (info.view == v) {
-
mFooterViewInfos.remove(i);
-
-
mAreAllFixedViewsSelectable =
-
areAllListInfosSelectable(mHeaderViewInfos)
-
&& areAllListInfosSelectable(mFooterViewInfos);
-
-
return true;
-
}
-
}
-
-
return false;
-
}
-
-
public int getCount() {
-
if (mAdapter != null) {
-
return getFootersCount() + getHeadersCount() + mAdapter.getCount();
-
} else {
-
return getFootersCount() + getHeadersCount();
-
}
-
}
-
-
public boolean areAllItemsEnabled() {
-
if (mAdapter != null) {
-
return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
-
} else {
-
return true;
-
}
-
}
-
-
public boolean isEnabled(int position) {
-
// Header (negative positions will throw an IndexOutOfBoundsException)
-
int numHeaders = getHeadersCount();
-
if (position < numHeaders) {
-
return mHeaderViewInfos.get(position).isSelectable;
-
}
-
-
// Adapter
-
final int adjPosition = position - numHeaders;
-
int adapterCount = 0;
-
if (mAdapter != null) {
-
adapterCount = mAdapter.getCount();
-
if (adjPosition < adapterCount) {
-
return mAdapter.isEnabled(adjPosition);
-
}
-
}
-
-
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
-
return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable;
-
}
-
-
public Object getItem(int position) {
-
// Header (negative positions will throw an IndexOutOfBoundsException)
-
int numHeaders = getHeadersCount();
-
if (position < numHeaders) {
-
return mHeaderViewInfos.get(position).data;
-
}
-
-
// Adapter
-
final int adjPosition = position - numHeaders;
-
int adapterCount = 0;
-
if (mAdapter != null) {
-
adapterCount = mAdapter.getCount();
-
if (adjPosition < adapterCount) {
-
return mAdapter.getItem(adjPosition);
-
}
-
}
-
-
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
-
return mFooterViewInfos.get(adjPosition - adapterCount).data;
-
}
-
-
public long getItemId(int position) {
-
int numHeaders = getHeadersCount();
-
if (mAdapter != null && position >= numHeaders) {
-
int adjPosition = position - numHeaders;
-
int adapterCount = mAdapter.getCount();
-
if (adjPosition < adapterCount) {
-
return mAdapter.getItemId(adjPosition);
-
}
-
}
-
return -1;
-
}
-
-
public boolean hasStableIds() {
-
if (mAdapter != null) {
-
return mAdapter.hasStableIds();
-
}
-
return false;
-
}
-
-
public View getView(int position, View convertView, ViewGroup parent) {
-
// Header (negative positions will throw an IndexOutOfBoundsException)
-
int numHeaders = getHeadersCount();
-
if (position < numHeaders) {
-
return mHeaderViewInfos.get(position).view;
-
}
-
-
// Adapter
-
final int adjPosition = position - numHeaders;
-
int adapterCount = 0;
-
if (mAdapter != null) {
-
adapterCount = mAdapter.getCount();
-
if (adjPosition < adapterCount) {
-
return mAdapter.getView(adjPosition, convertView, parent);
-
}
-
}
-
-
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
-
return mFooterViewInfos.get(adjPosition - adapterCount).view;
-
}
-
-
public int getItemViewType(int position) {
-
int numHeaders = getHeadersCount();
-
if (mAdapter != null && position >= numHeaders) {
-
int adjPosition = position - numHeaders;
-
int adapterCount = mAdapter.getCount();
-
if (adjPosition < adapterCount) {
-
return mAdapter.getItemViewType(adjPosition);
-
}
-
}
-
-
return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
-
}
-
-
public int getViewTypeCount() {
-
if (mAdapter != null) {
-
return mAdapter.getViewTypeCount();
-
}
-
return 1;
-
}
-
-
public void registerDataSetObserver(DataSetObserver observer) {
-
if (mAdapter != null) {
-
mAdapter.registerDataSetObserver(observer);
-
}
-
}
-
-
public void unregisterDataSetObserver(DataSetObserver observer) {
-
if (mAdapter != null) {
-
mAdapter.unregisterDataSetObserver(observer);
-
}
-
}
-
-
public Filter getFilter() {
-
if (mIsFilterable) {
-
return ((Filterable) mAdapter).getFilter();
-
}
-
return null;
-
}
-
-
public ListAdapter getWrappedAdapter() {
-
return mAdapter;
-
}
-
}
核心源码分析:
1. HeaderViewListAdapter构造函数
它有3个参数,头、尾、正常条目的mAdapter,这个与我们(一)中分析的一样,也是传递这3个内容。
2. getCount()函数
这个函数返回真正的条目数:headerCount + footerCount + mAdapter.count
3. getItem(int position)
返回position条目上要显示的数据: 这里有也是3部分,其中第一个if判断该position是否是头部,第二个if判断是否是中间条目,最后是尾部条目,根据不同的情况返回对应的数据
return mHeaderViewInfos.get(position).data;
return mAdapter.getItem(adjPosition);//这个是创建普通adapter时,new adapter的时候传递给adapter的数据集合的position索引里的数据、
return mFooterViewInfos.get(adjPosition - adapterCount).data;//构造函数传递过来的数组
4.getview函数
这个函数再熟悉不过了,就是为条目返回要显示的布局VIEW以及可在这个函数里为VIEW中元素赋值,如为条目上的TextView赋值一个字符串文本。在这里也和3中一样返回对应的VIEW(头部VIEW、普通条目VIEW、尾部VIEW):
return mHeaderViewInfos.get(position).view;
return mAdapter.getView(adjPosition,convertView,parent);
return mFooterViewInfos.get(adjPosition - adapterCount).view;
这里提醒一下,mAdapter就是我们普通条目的MyAdapter,就是我们在不需要添加 头尾部的时候,使用listview显示数据得先创建一个MyAdapter,比如MyAdapter继承BaseAdapter,然后重写getview等方法,我相信你懂我说的。
总结一下,观察以上HeaderViewListAdapter的4个函数我们会发现它们总是离不开mAdapter,也就是说它们总要改造一番:在原mAdapter的基础上都额外涉及到了header和footer,只有这样才能满足listview正常显示头尾部的需求。
四、模仿(三)中的HeaderViewListAdapter为RecyclerView自定义适合它的
HeaderViewListAdapter
-
package com.anyikang.volunteer.sos.recyclerview;
-
-
import android.support.v7.widget.RecyclerView.Adapter;
-
import android.support.v7.widget.RecyclerView.ViewHolder;
-
import android.view.View;
-
import android.view.ViewGroup;
-
-
import java.util.ArrayList;
-
-
public class HeaderViewAdapterForRecycler extends Adapter {
-
private Adapter mAdapter;
-
-
ArrayList<View> mHeaderViewInfos;
-
ArrayList<View> mFooterViewInfos;
-
-
/**
-
*
-
* @param headerViewInfos 头布局VIEW
-
* @param footerViewInfos 尾布局VIWE
-
* @param adapter 普通ITEM的适配器adapter
-
*/
-
public HeaderViewAdapterForRecycler (ArrayList<View> headerViewInfos,
-
ArrayList<View> footerViewInfos, Adapter adapter) {
-
mAdapter = adapter;
-
-
if (headerViewInfos == null) {
-
mHeaderViewInfos = new ArrayList<View>();
-
} else {
-
mHeaderViewInfos = headerViewInfos;
-
}
-
-
if (footerViewInfos == null) {
-
mFooterViewInfos = new ArrayList<View>();
-
} else {
-
mFooterViewInfos = footerViewInfos;
-
}
-
}
-
-
/**
-
*
-
* @return
-
*/
-
@Override
-
public int getItemCount() {
-
if (mAdapter != null) {
-
//从此列表的条目数为:头+尾+普通条目适配器的 条数(即列表中间条目数)
-
return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();
-
} else {
-
return getFootersCount() + getHeadersCount();
-
}
-
}
-
-
@Override
-
public void onBindViewHolder(ViewHolder holder, int position) {
-
-
-
int numHeaders = getHeadersCount();
-
if (position < numHeaders) {
-
//判断是头布局的话,不用填充数据因为我们已经在 MainActivity里为头VIEW填充了数据
-
return ;
-
}
-
-
final int adjPosition = position - numHeaders;
-
int adapterCount = 0;
-
if (mAdapter != null) {
-
adapterCount = mAdapter.getItemCount();
-
-
//中间条目的数据 我们直接调度 普通条目adapter的onBindViewHolder来为条目VIEW填充数据
-
if (adjPosition < adapterCount) {
-
mAdapter.onBindViewHolder(holder, adjPosition);
-
return ;
-
}
-
}
-
-
//其它情况就是尾布局VIEW,不用填充数据因为我们已经在 MainActivity里为尾VIEW填充了数据
-
-
}
-
-
-
/**
-
* 得到条目类型:INVALID_TYPE表示当前条目是头部
-
* @param position
-
* @return
-
*/
-
@Override
-
public int getItemViewType(int position) {
-
-
//
-
int numHeaders = getHeadersCount();
-
if (position < numHeaders) {//是头部
-
return -1;
-
}
-
//正常条目部分
-
// Adapter
-
final int adjPosition = position - numHeaders;
-
int adapterCount = 0;
-
if (mAdapter != null) {
-
adapterCount = mAdapter.getItemCount();
-
if (adjPosition < adapterCount) {
-
return mAdapter.getItemViewType(adjPosition);
-
}
-
}
-
//footer部分
-
return 1;
-
}
-
-
/**
-
* 根据getItemViewType获得的viewType来返回对应的布局
-
* @param parent
-
* @param viewType
-
* @return
-
*/
-
@Override
-
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-
//header
-
if(viewType == -1){
-
return new HeaderViewHolder(mHeaderViewInfos.get(0));
-
}else if(viewType == 1){//footer
-
return new HeaderViewHolder(mFooterViewInfos.get(0));
-
}
-
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
-
return mAdapter.onCreateViewHolder(parent, viewType);
-
}
-
-
public int getHeadersCount() {
-
return mHeaderViewInfos.size();
-
}
-
-
public int getFootersCount() {
-
return mFooterViewInfos.size();
-
}
-
-
private static class HeaderViewHolder extends ViewHolder{
-
-
public HeaderViewHolder(View view) {
-
super(view);
-
}
-
}
-
-
}
2. 普通条目的adapter
由于HeaderViewAdapterForRecycler 重新包装了普通条目的adapter,我们在此有必要帖出普通(中间条目)adapter的源码:
-
package com.anyikang.volunteer.sos.recyclerview;
-
-
import android.support.v7.widget.RecyclerView;
-
import android.view.View;
-
import android.view.ViewGroup;
-
import android.widget.ImageView;
-
-
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> {
-
-
private int[] list;
-
private OnItemClickListener mOnItemClickListener;
-
-
public MyRecyclerAdapter(int[] list) {
-
this.list = list;
-
}
-
-
class MyViewHolder extends RecyclerView.ViewHolder{
-
ImageView imv;
-
-
public MyViewHolder(View view) {
-
super(view);
-
imv = (ImageView)view.findViewById(R.id.imv);
-
}
-
-
}
-
@Override
-
public int getItemCount() {
-
return list.length;
-
}
-
-
@Override
-
public void onBindViewHolder(MyViewHolder holder, final int position) {
-
holder.imv.setImageResource(list[position]);
-
-
if(mOnItemClickListener!=null){
-
holder.itemView.setOnClickListener(new View.OnClickListener() {
-
-
@Override
-
public void onClick(View v) {
-
mOnItemClickListener.onItemClick(v, position);
-
}
-
});
-
}
-
}
-
-
-
@Override
-
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int arg1) {
-
MyViewHolder holder = new MyViewHolder(View.inflate(viewGroup.getContext(), R.layout.list_item2, null));
-
return holder;
-
}
-
-
-
/*public void addData(int position){
-
list.add(position,"additem"+position);
-
notifyItemInserted(position);
-
}
-
public void removeData(int position){
-
list.remove(position);
-
notifyItemRemoved(position);
-
}*/
-
-
public interface OnItemClickListener{
-
void onItemClick(View view, int position);
-
}
-
-
public void setOnItemClickListener(OnItemClickListener listener){
-
this.mOnItemClickListener = listener;
-
}
-
}
五、如何使用我们自定义好的MyRecyclerView与HeaderViewAdapterForRecycler
梳理使用过程:
(1)在MainAcitivity的布局文件里声明MyRecyclerView:
-
<com.anyikang.volunteer.sos.recyclerview.MyRecyclerView
-
android:layout_margin="50dp"
-
android:id="@+id/recylerview"
-
android:layout_width="match_parent"
-
android:layout_height="wrap_content"
-
/>
(2)先定义普通adapter(用于显示中间条目)
代码,见(四)中的 第2节
(3)定义HeaderViewAdapterForRecycler(具有处理理头部和尾部能力)
它相当于一个代理类,可以根据是否有头或尾的需求来重新封装了普通adapter
代码,见(四)中的 第1节
(4)在MainActivity里使用全新的RecyclerView
核心步骤:
-
//实例化布局中的recylerview控件
-
recylerview = (MyRecyclerView)findViewById(R.id.recylerview);
-
-
recylerview.addHeaderView(head); //添加头部
recylerview.addFooterView(footer);//添加尾部
adapter = new MyRecyclerAdapter(list); //普通条目(中间条目)的adapter
recylerview.setAdapter(adapter); // setAdapter里发现有header或footer就会 将我们的adapter“偷梁换柱”
六、回马枪
重温原理, 直接上图:
文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/80411911
- 点赞
- 收藏
- 关注作者
评论(0)