RecyclerView之Header和Footer的添加
2017-06-27 本文已影响0人
小和尚恋红尘
一,添加Header和Footer
在Adapter中新添加一些int值,用于区分添加Header,Footer,还是都没有添加
val TYPE_FOOTER = 1//添加Footer
val TYPE_HEADER = 2//添加Header
val TYPE_NORMAL = 0//两者都没有添加
在Adapter中新暴漏两个方法,用于设置Header和Footer
fun setHeaderView(hv: View){
headerView = hv
notifyItemInserted(0)
}
fun setFooterView(fv: View){
footerView = fv
notifyItemInserted(itemCount - 1)
}
根据是否添加了Header和Footer来设置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
}
复写getItemViewType
方法,用于区分是否需要添加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
中根据设置的标记来分别绑定布局文件
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位置的值为数据中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中直接设置Header
和Footer
的布局,因此需要在Activity中进行设置
/**
* 添加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)
}
效果图如下
device-2017-06-27-094800.png
上面效果使用的显示方式为LinearLayoutManager
,现在换成GridLayoutManager
,运行,效果图为:
可以看出,
Header
和Footer
都只是占据了一个Item的位置,而我们希望的是占据一行,所以这样明显不符合我们的要求。在GridLayoutManager
中提供了setSpanSizeLookup
方法,它就是用来设置列数的,我们可以通过调用此方法来满足我们的要求。在Adapter中,复写
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;
}
});
}
}
}
运行程序,发现上面的Kotlin
代码并没有实现,我们的效果。而
Java
代码能够正确实现我们的效果,图为:
当然也并不是只能在Adapter中进行设置,也可以直接在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
}
}
上面两种代码都可以实现上图效果。
现在换成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);
}
}
运行程序,效果图为:
device-2017-06-27-152155.png
这样RecyclerView中三种显示方式,都能正确显示Header
和Footer
。
好了,RecyclerView添加Header
和Footer
就介绍到这里,不足之处请各位指正,谢谢。下一篇讲解RecyclerView之上拉加载下拉刷新