一,添加Header和Footer
在Adapter中新添加一些int值,用于區(qū)分添加Header,F(xiàn)ooter,還是都沒有添加
val TYPE_FOOTER = 1//添加Footer
val TYPE_HEADER = 2//添加Header
val TYPE_NORMAL = 0//兩者都沒有添加
在Adapter中新暴漏兩個方法,用于設(shè)置Header和Footer
fun setHeaderView(hv: View){
headerView = hv
notifyItemInserted(0)
}
fun setFooterView(fv: View){
footerView = fv
notifyItemInserted(itemCount - 1)
}
根據(jù)是否添加了Header和Footer來設(shè)置itemCount的值
override fun getItemCount(): Int{
if (headerView != null && footerView != null)
return items.size + 2
else if(headerView == null && footerView == null)
return items.size
else
return items.size + 1
}
復(fù)寫getItemViewType方法,用于區(qū)分是否需要添加Header和Footer
override fun getItemViewType(position: Int): Int {
if (headerView == null && footerView == null)
return TYPE_NORMAL
if(position == 0)
return TYPE_HEADER
if(position == itemCount-1)
return TYPE_FOOTER
return TYPE_NORMAL
}
在onCreateViewHolder中根據(jù)設(shè)置的標(biāo)記來分別綁定布局文件
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
if (headerView != null && viewType == TYPE_HEADER)
return ViewHolder(headerView!!)
if (footerView != null && viewType == TYPE_FOOTER)
return ViewHolder(footerView!!)
val view = LayoutInflater.from(context).inflate(R.layout.item_rc_4st, parent, false)
view.setOnClickListener { view -> listener?.onItemClick(view, view.tag as Int) }
return ViewHolder(view)
}
或者寫成
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
if (headerView != null && viewType == TYPE_HEADER) {
val view = LayoutInflater.from(context).inflate(R.layout.header, parent, false)
return ViewHolder(view)
}
if (footerView != null && viewType == TYPE_FOOTER) {
val view = LayoutInflater.from(context).inflate(R.layout.footer, parent, false)
return ViewHolder(view)
}
val view = LayoutInflater.from(context).inflate(R.layout.item_rc_4st, parent, false)
view.setOnClickListener { view -> listener?.onItemClick(view, view.tag as Int) }
return ViewHolder(view)
}
在onBindViewHolder增加多Footer和Header的處理。如果添加了Header的話,那么Header的位置為‘0’,此時pos位置的值為數(shù)據(jù)中pos-1位置的值
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (getItemViewType(position) == TYPE_HEADER) return
else if (getItemViewType(position) == TYPE_FOOTER) return
else{
if (holder is RecyclerViewAddHeaderAndFooterAdapter.ViewHolder){
Log.e("hjd", "position->"+ position)
val positionTemp = if (headerView == null) position else position -1//計算pos位置
if (positionTemp < items.size){
holder.tv!!.text = items[positionTemp]
holder.itemView.tag= positionTemp
}
}
}
}
這樣添加Header和Footer就完成了,下面來看Adapter中的完整代碼
class RecyclerViewAddHeaderAndFooterAdapter(var context: Context, var items: ArrayList<String>):RecyclerView.Adapter<RecyclerViewAddHeaderAndFooterAdapter.ViewHolder>(){
companion object{
val TYPE_FOOTER = 1//添加Footer
val TYPE_HEADER = 2//添加Header
val TYPE_NORMAL = 0//兩者都沒有添加
var headerView: View? = null
var footerView: View? = null
}
var list = ArrayList<String>()
init {
list = items
}
fun setHeaderView(hv: View){
headerView = hv
notifyItemInserted(0)
}
fun setFooterView(fv: View){
footerView = fv
notifyItemInserted(itemCount - 1)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (getItemViewType(position) == TYPE_HEADER) return
else if (getItemViewType(position) == TYPE_FOOTER) return
else{
if (holder is RecyclerViewAddHeaderAndFooterAdapter.ViewHolder){
Log.e("hjd", "position->"+ position)
val positionTemp = if (headerView == null) position else position -1
if (positionTemp < items.size){
holder.tv!!.text = items[positionTemp]
holder.itemView.tag= positionTemp
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
if (headerView != null && viewType == TYPE_HEADER)
return ViewHolder(headerView!!)
if (footerView != null && viewType == TYPE_FOOTER)
return ViewHolder(footerView!!)
val view = LayoutInflater.from(context).inflate(R.layout.item_rc_4st, parent, false)
view.setOnClickListener { view -> listener?.onItemClick(view, view.tag as Int) }
return ViewHolder(view)
}
override fun getItemCount(): Int{
if (headerView != null && footerView != null)
return items.size + 2
else if(headerView == null && footerView == null)
return items.size
else
return items.size + 1
}
override fun getItemViewType(position: Int): Int {
if (headerView == null && footerView == null)
return TYPE_NORMAL
if(position == 0)
return TYPE_HEADER
if(position == itemCount-1)
return TYPE_FOOTER
return TYPE_NORMAL
}
class ViewHolder(itemTv: View):RecyclerView.ViewHolder(itemTv){
var tv: TextView? = null
init {
if (headerView != itemTv && footerView != itemTv) {
tv = itemTv.findViewById(R.id.tv) as TextView
}
}
}
private var listener: OnItemClickListener?=null
fun setOnItemClickListener(l: OnItemClickListener): Unit{
this.listener = l
}
interface OnItemClickListener{
fun onItemClick(view: View, pos: Int)
}
fun addItem(pos: Int){
list.add(pos, "Add item"+ pos)
notifyItemInserted(pos)
}
fun delItem(pos: Int){
list.removeAt(pos)
notifyItemRemoved(pos)
}
}
因為我沒有在上面的Adapter中直接設(shè)置Header和Footer的布局,因此需要在Activity中進行設(shè)置
/**
* 添加HeaderView
*/
fun setHeaderView(rv: RecyclerView, adapter: RecyclerViewAddHeaderAndFooterAdapter){
val hv = LayoutInflater.from(this).inflate(R.layout.header, rv, false)
adapter.setHeaderView(hv)
}
/**
* 添加FooterView
*/
fun setFooterView(rv: RecyclerView, adapter: RecyclerViewAddHeaderAndFooterAdapter){
val hv = LayoutInflater.from(this).inflate(R.layout.footer, rv, false)
adapter.setFooterView(hv)
}
效果圖如下

上面效果使用的顯示方式為LinearLayoutManager,現(xiàn)在換成GridLayoutManager,運行,效果圖為:

可以看出,
Header和Footer都只是占據(jù)了一個Item的位置,而我們希望的是占據(jù)一行,所以這樣明顯不符合我們的要求。在GridLayoutManager中提供了setSpanSizeLookup方法,它就是用來設(shè)置列數(shù)的,我們可以通過調(diào)用此方法來滿足我們的要求。在Adapter中,復(fù)寫
onAttachedToRecyclerView方法
//此為Kotlin代碼
override fun onAttachedToRecyclerView(recyclerView: RecyclerView?) {
val manager = recyclerView!!.layoutManager
if (manager == null){
Log.e("hjd", "layoutManager == null")
}else {
if (manager is GridLayoutManager) {
val glm: GridLayoutManager = manager
glm.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
if (getItemViewType(position) == TYPE_HEADER || getItemViewType(position) == TYPE_FOOTER)
return glm.spanCount
else
return 1
}
}
}
}
}
//此為Java代碼
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager == null){
Log.e("hjd", "layoutManager == null");
}else {
if (layoutManager instanceof GridLayoutManager){
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (getItemViewType(position) == TYPE_FOOTER || getItemViewType(position) == TYPE_HEADER)
return gridLayoutManager.getSpanCount();
else
return 1;
}
});
}
}
}
運行程序,發(fā)現(xiàn)上面的Kotlin代碼并沒有實現(xiàn),我們的效果。而
Java代碼能夠正確實現(xiàn)我們的效果,圖為:

當(dāng)然也并不是只能在Adapter中進行設(shè)置,也可以直接在Activity中進行:
//此為Kotlin代碼
gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup(){
override fun getSpanSize(position: Int): Int {
if (mAdapter!!.getItemViewType(position) == 1 || mAdapter!!.getItemViewType(position) == 2){
return gridLayoutManager.spanCount
}else
return 1
}
}
上面兩種代碼都可以實現(xiàn)上圖效果。
現(xiàn)在換成StaggeredGridLayoutManager,運行,效果圖為:

也只是占用一個Item的位置,因此我們也要進行配置,以滿足我們的要求
//此為Kotlin代碼
override fun onViewAttachedToWindow(holder: ViewHolder?) {
super.onViewAttachedToWindow(holder)
val layoutParams = holder!!.itemView.layoutParams
if (layoutParams != null && layoutParams is StaggeredGridLayoutManager.LayoutParams) {
layoutParams.isFullSpan = getItemViewType(holder.layoutPosition) == TYPE_HEADER || getItemViewType(holder.layoutPosition) == TYPE_FOOTER
}
}
//此為Java代碼
@Override
public void onViewAttachedToWindow(ViewHodler holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams){
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) layoutParams;
lp.setFullSpan(getItemViewType(holder.getLayoutPosition())== TYPE_HEADER || getItemViewType(holder.getLayoutPosition()) == TYPE_FOOTER);
}
}
運行程序,效果圖為:

這樣RecyclerView中三種顯示方式,都能正確顯示Header和Footer。
好了,RecyclerView添加Header和Footer就介紹到這里,不足之處請各位指正,謝謝。下一篇講解RecyclerView之上拉加載下拉刷新