这里并没有重写recyclerview,只是对adapter进行了封装。
封装的adapter
/**
*
* @fuction recycleview 加载更多用的adpter
* @date 2018/9/15
* @author zhou
*/
abstract class RVLoadMoreAdapter<T>(
protected var mContext: Context,
private val recyclerView: RecyclerView,
private val res_item_id: Int,
var dataSet: MutableList<T>
) : RecyclerView.Adapter<RViewHolder>() {
val TAG = RVLoadMoreAdapter::class.java.simpleName
var isLoading = false
private var canLoadMore = false
private var loadMoreComplete = true
private var loadingMore: OnLoadingMore? = null
protected var mOnItemClickListener: OnItemClickListener? = null
private var lastPositions: IntArray? = null
private var footViewholder: RViewHolder? = null
private var headerView: View? = null
fun findMax(lastPositions: IntArray): Int {
var max = lastPositions[0]
for (value in lastPositions) {
if (value > max) {
max = value
}
}
return max
}
fun loadMore() {
loadingMore?.also {
loadMoreComplete = true
Loading(true)
it.onLoadMore()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RViewHolder {
val holder: RViewHolder
if (viewType == TYPE_HEAD) {
holder = RViewHolder.createViewHolder(mContext, headerView!!)
} else if (viewType == TYPE_LOAD_MORE) {
if (footViewholder == null) {
footViewholder = RViewHolder.createViewHolder(mContext, parent, R.layout.loadmore_default_footer)
}
holder = footViewholder!!
showNormal()
} else {
holder = RViewHolder.createViewHolder(mContext, parent, res_item_id)
}
onViewHolderCreated(holder, holder.convertView, viewType)
setListener(parent, holder, viewType)
return holder
}
open fun onViewHolderCreated(
holder: RViewHolder,
itemView: View,
viewType: Int
) {
}
override fun onBindViewHolder(holder: RViewHolder, position: Int) {
if (getItemViewType(position) == TYPE_LOAD_MORE) {
return
}
if (getItemViewType(position) == TYPE_HEAD) {
return
}
val p = if (headerView != null) position - 1 else position
val t = dataSet[p]
convert(holder, t, p)
}
protected abstract fun convert(holder: RViewHolder, t: T, position: Int)
override fun getItemCount(): Int {
var size = dataSet.size
if (headerView != null) {
size++
}
if (canLoadMore) {
size++
}
return size
}
override fun getItemViewType(position: Int): Int {
if (position == 0) {
if (headerView != null) {
return TYPE_HEAD
}
}
if (canLoadMore) {
if (position == itemCount - 1) {
return TYPE_LOAD_MORE
}
}
return TYPE_NORMAL
}
fun setLoadingMore(loadingMore: OnLoadingMore?) {
this.loadingMore = loadingMore
}
fun Loading(loading: Boolean) {
isLoading = loading
showNormal()
}
fun setLoadMoreComplete(complete: Boolean) {
canLoadMore = loadingMore != null
loadMoreComplete = complete
}
private var custom_layout_empty: LinearLayout? = null
fun showNormal() {
canLoadMore = loadingMore != null
if (!canLoadMore) {
return
}
if (footViewholder == null) {
return
}
if (loadMoreComplete) {
footViewholder!!.setVisible(R.id.layout_empty_default, true)
val loadmore_default_footer_tv = footViewholder!!.getView<TextView>(R.id.loadmore_default_footer_tv)
if (isLoading) {
loadmore_default_footer_tv.text = "加载中"
loadmore_default_footer_tv.setOnClickListener(null)
footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, true)
} else {
loadmore_default_footer_tv.text = "点击加载更多"
loadmore_default_footer_tv.setOnClickListener { loadMore() }
footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
}
custom_layout_empty?.visibility = View.GONE
} else {
if (dataSet.size > 0) {
footViewholder!!.setVisible(R.id.layout_empty_default, true)
footViewholder!!.setText(R.id.loadmore_default_footer_tv, "无更多数据")
footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
custom_layout_empty?.visibility = View.GONE
} else {
footViewholder!!.setVisible(R.id.layout_empty_default, false)
if (custom_layout_empty == null) {
var stub_import = footViewholder!!.itemView.findViewById<ViewStub>(R.id.stub_import)
if (stub_import != null) {
stub_import.inflate()
stub_import = null
}
custom_layout_empty = footViewholder!!.getView(R.id.custom_layout_empty)
if (!TextUtils.isEmpty(emptyText)) {
val tv_empty = custom_layout_empty!!.findViewById<TextView>(R.id.tv_empty)
tv_empty.text = emptyText
}
val iv_empty = custom_layout_empty!!.findViewById<ImageView>(R.id.iv_empty)
iv_empty.setImageResource(emptyRes)
}
custom_layout_empty!!.visibility = View.VISIBLE
}
}
}
fun addData(t: T) {
dataSet!!.add(t)
notifyDataSetChanged()
}
interface OnLoadingMore {
fun onLoadMore()
}
protected fun setListener(
parent: ViewGroup?,
viewHolder: RViewHolder,
viewType: Int
) {
viewHolder.convertView.setOnClickListener(View.OnClickListener { v ->
mOnItemClickListener?.also {
val position = viewHolder.adapterPosition
if (TYPE_HEAD == getItemViewType(position)) {
return@OnClickListener
}
if (TYPE_LOAD_MORE == getItemViewType(position)) {
return@OnClickListener
}
val p = if (headerView != null) position - 1 else position
it.onItemClick(v, viewHolder, p)
}
})
viewHolder.convertView.setOnLongClickListener(OnLongClickListener { v ->
mOnItemClickListener?.also {
val position = viewHolder.adapterPosition
if (TYPE_HEAD == getItemViewType(position)) {
return@OnLongClickListener false
}
if (TYPE_LOAD_MORE == getItemViewType(position)) {
return@OnLongClickListener false
}
val p = if (headerView != null) position - 1 else position
return@OnLongClickListener it.onItemLongClick(v, viewHolder, p)
}
false
})
}
interface OnItemClickListener {
fun onItemClick(
view: View,
holder: ViewHolder,
position: Int
)
fun onItemLongClick(
view: View,
holder: ViewHolder,
position: Int
): Boolean
}
fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) {
mOnItemClickListener = onItemClickListener
}
fun addHeaderView(view: View?) {
headerView = view
}
fun setCanLoadMore(canLoadMore: Boolean) {
this.canLoadMore = canLoadMore
}
private var emptyText: String? = null
private var emptyRes = R.drawable.icon_empty_default
fun setEmptyContent(txt: String?, res: Int) {
emptyText = txt
emptyRes = res
}
fun setEmptyRes(emptyRes: Int) {
this.emptyRes = emptyRes
}
fun setEmptyText(emptyText: String?) {
this.emptyText = emptyText
}
companion object {
const val TYPE_NORMAL = 100
const val TYPE_HEAD = 101
const val TYPE_LOAD_MORE = 102
}
init {
//监听recylerview的滑动
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy <= 0) {
return
}
if (loadMoreComplete && canLoadMore && !isLoading) {
var lastVisibleItem = 0
val layoutManager = recyclerView.layoutManager
if (layoutManager is LinearLayoutManager) {
lastVisibleItem = layoutManager.findLastVisibleItemPosition()
} else if (layoutManager is GridLayoutManager) {
lastVisibleItem = layoutManager.findLastVisibleItemPosition()
} else if (layoutManager is StaggeredGridLayoutManager) {
if (lastPositions == null) {
lastPositions = IntArray(layoutManager.spanCount)
}
layoutManager.findLastVisibleItemPositions(lastPositions)
lastVisibleItem = findMax(lastPositions!!)
} else {
throw RuntimeException(
"Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager"
)
}
if (lastVisibleItem + 1 == itemCount) {
loadMore()
}
}
}
})
}
}
该adapter分别可以适配线性列表,grid列表,瀑布流列表三种布局的加载更多。
使用方法:线性列表
val layoutManager = LinearLayoutManager(this); //线性布局
recyclerview.layoutManager = layoutManager
homeAdapter = object: RVLoadMoreAdapter<String>(this@AdapterMoreLoad1Activity,recyclerview,R.layout.item_rv_txt, mDatas){
override fun convert(holder: RViewHolder, t: String, position: Int) {
holder.setText(R.id.txt,mDatas[position])
}
}
recyclerview.adapter = homeAdapter
homeAdapter!!.setOnItemClickListener(object: RVLoadMoreAdapter.OnItemClickListener{
override fun onItemClick(view: View, holder: RecyclerView.ViewHolder, position: Int) {
}
override fun onItemLongClick(
view: View,
holder: RecyclerView.ViewHolder,
position: Int
): Boolean {
return false
}
})
homeAdapter!!.setLoadingMore(object: RVLoadMoreAdapter.OnLoadingMore{
override fun onLoadMore() {
downJson(mCurrentPage+1)
}
})
在downjson是可以是接口获取数据,获取完数据需要做一些操作,如下
private fun downJson(page: Int) {
Handler().postDelayed(Runnable {
swipe_layout.isRefreshing = false
if(page == 1){
mDatas.clear()
homeAdapter!!.setLoadMoreComplete(true)
}
mCurrentPage = page
val datalist = ArrayList<String>()
if(page == 3){ //模拟滑动到最底部
for (i in 1..7){
datalist.add("RecyclerView使用$i")
}
}else{
for (i in 1..20){
datalist.add("RecyclerView使用$i")
}
}
mDatas.addAll(datalist)
if (datalist.size < 20) {
homeAdapter!!.setLoadMoreComplete(false)
}
homeAdapter!!.notifyDataSetChanged()
homeAdapter!!.Loading(false)
},1000)
}
具体操作大家可以自己分析,还是很容易理解。
这里特别注意:用grid列表的时候需要加入
layoutManager.spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (homeAdapter!!.getItemViewType(position) == RVLoadMoreAdapter.TYPE_LOAD_MORE) {
2
} else {
1
}
}
}
这样加载更多的底部布局才能跨列显示。上面的2是因为我用的是2列的grid,如果是3列就是3,以此类推。
瀑布流的时候,需要重写onViewHolderCreated的方法,解决加载更多的跨列问题,如下
homeAdapter = object: RVLoadMoreAdapter<String>(this@AdapterMoreLoad3Activity,recyclerview,R.layout.item_rv_txt, mDatas){
override fun onViewHolderCreated(holder: RViewHolder, itemView: View, viewType: Int) {
super.onViewHolderCreated(holder, itemView, viewType)
if (viewType === TYPE_LOAD_MORE) {
val lp = holder.itemView.layoutParams
if (lp != null && lp is StaggeredGridLayoutManager.LayoutParams) {
lp.isFullSpan = true
}
}
}
override fun convert(holder: RViewHolder, t: String, position: Int) {
holder.setText(R.id.txt,mDatas[position])
}
}
这里并没有重写recyclerview,只是对adapter进行了封装。
封装的adapter
/**
*
* @fuction recycleview 加载更多用的adpter
* @date 2018/9/15
* @author zhou
*/
abstract class RVLoadMoreAdapter<T>(
protected var mContext: Context,
private val recyclerView: RecyclerView,
private val res_item_id: Int,
var dataSet: MutableList<T>
) : RecyclerView.Adapter<RViewHolder>() {
val TAG = RVLoadMoreAdapter::class.java.simpleName
var isLoading = false
private var canLoadMore = false
private var loadMoreComplete = true
private var loadingMore: OnLoadingMore? = null
protected var mOnItemClickListener: OnItemClickListener? = null
private var lastPositions: IntArray? = null
private var footViewholder: RViewHolder? = null
private var headerView: View? = null
fun findMax(lastPositions: IntArray): Int {
var max = lastPositions[0]
for (value in lastPositions) {
if (value > max) {
max = value
}
}
return max
}
fun loadMore() {
loadingMore?.also {
loadMoreComplete = true
Loading(true)
it.onLoadMore()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RViewHolder {
val holder: RViewHolder
if (viewType == TYPE_HEAD) {
holder = RViewHolder.createViewHolder(mContext, headerView!!)
} else if (viewType == TYPE_LOAD_MORE) {
if (footViewholder == null) {
footViewholder = RViewHolder.createViewHolder(mContext, parent, R.layout.loadmore_default_footer)
}
holder = footViewholder!!
showNormal()
} else {
holder = RViewHolder.createViewHolder(mContext, parent, res_item_id)
}
onViewHolderCreated(holder, holder.convertView, viewType)
setListener(parent, holder, viewType)
return holder
}
open fun onViewHolderCreated(
holder: RViewHolder,
itemView: View,
viewType: Int
) {
}
override fun onBindViewHolder(holder: RViewHolder, position: Int) {
if (getItemViewType(position) == TYPE_LOAD_MORE) {
return
}
if (getItemViewType(position) == TYPE_HEAD) {
return
}
val p = if (headerView != null) position - 1 else position
val t = dataSet[p]
convert(holder, t, p)
}
protected abstract fun convert(holder: RViewHolder, t: T, position: Int)
override fun getItemCount(): Int {
var size = dataSet.size
if (headerView != null) {
size++
}
if (canLoadMore) {
size++
}
return size
}
override fun getItemViewType(position: Int): Int {
if (position == 0) {
if (headerView != null) {
return TYPE_HEAD
}
}
if (canLoadMore) {
if (position == itemCount - 1) {
return TYPE_LOAD_MORE
}
}
return TYPE_NORMAL
}
fun setLoadingMore(loadingMore: OnLoadingMore?) {
this.loadingMore = loadingMore
}
fun Loading(loading: Boolean) {
isLoading = loading
showNormal()
}
fun setLoadMoreComplete(complete: Boolean) {
canLoadMore = loadingMore != null
loadMoreComplete = complete
}
private var custom_layout_empty: LinearLayout? = null
fun showNormal() {
canLoadMore = loadingMore != null
if (!canLoadMore) {
return
}
if (footViewholder == null) {
return
}
if (loadMoreComplete) {
footViewholder!!.setVisible(R.id.layout_empty_default, true)
val loadmore_default_footer_tv = footViewholder!!.getView<TextView>(R.id.loadmore_default_footer_tv)
if (isLoading) {
loadmore_default_footer_tv.text = "加载中"
loadmore_default_footer_tv.setOnClickListener(null)
footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, true)
} else {
loadmore_default_footer_tv.text = "点击加载更多"
loadmore_default_footer_tv.setOnClickListener { loadMore() }
footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
}
custom_layout_empty?.visibility = View.GONE
} else {
if (dataSet.size > 0) {
footViewholder!!.setVisible(R.id.layout_empty_default, true)
footViewholder!!.setText(R.id.loadmore_default_footer_tv, "无更多数据")
footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
custom_layout_empty?.visibility = View.GONE
} else {
footViewholder!!.setVisible(R.id.layout_empty_default, false)
if (custom_layout_empty == null) {
var stub_import = footViewholder!!.itemView.findViewById<ViewStub>(R.id.stub_import)
if (stub_import != null) {
stub_import.inflate()
stub_import = null
}
custom_layout_empty = footViewholder!!.getView(R.id.custom_layout_empty)
if (!TextUtils.isEmpty(emptyText)) {
val tv_empty = custom_layout_empty!!.findViewById<TextView>(R.id.tv_empty)
tv_empty.text = emptyText
}
val iv_empty = custom_layout_empty!!.findViewById<ImageView>(R.id.iv_empty)
iv_empty.setImageResource(emptyRes)
}
custom_layout_empty!!.visibility = View.VISIBLE
}
}
}
fun addData(t: T) {
dataSet!!.add(t)
notifyDataSetChanged()
}
interface OnLoadingMore {
fun onLoadMore()
}
protected fun setListener(
parent: ViewGroup?,
viewHolder: RViewHolder,
viewType: Int
) {
viewHolder.convertView.setOnClickListener(View.OnClickListener { v ->
mOnItemClickListener?.also {
val position = viewHolder.adapterPosition
if (TYPE_HEAD == getItemViewType(position)) {
return@OnClickListener
}
if (TYPE_LOAD_MORE == getItemViewType(position)) {
return@OnClickListener
}
val p = if (headerView != null) position - 1 else position
it.onItemClick(v, viewHolder, p)
}
})
viewHolder.convertView.setOnLongClickListener(OnLongClickListener { v ->
mOnItemClickListener?.also {
val position = viewHolder.adapterPosition
if (TYPE_HEAD == getItemViewType(position)) {
return@OnLongClickListener false
}
if (TYPE_LOAD_MORE == getItemViewType(position)) {
return@OnLongClickListener false
}
val p = if (headerView != null) position - 1 else position
return@OnLongClickListener it.onItemLongClick(v, viewHolder, p)
}
false
})
}
interface OnItemClickListener {
fun onItemClick(
view: View,
holder: ViewHolder,
position: Int
)
fun onItemLongClick(
view: View,
holder: ViewHolder,
position: Int
): Boolean
}
fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) {
mOnItemClickListener = onItemClickListener
}
fun addHeaderView(view: View?) {
headerView = view
}
fun setCanLoadMore(canLoadMore: Boolean) {
this.canLoadMore = canLoadMore
}
private var emptyText: String? = null
private var emptyRes = R.drawable.icon_empty_default
fun setEmptyContent(txt: String?, res: Int) {
emptyText = txt
emptyRes = res
}
fun setEmptyRes(emptyRes: Int) {
this.emptyRes = emptyRes
}
fun setEmptyText(emptyText: String?) {
this.emptyText = emptyText
}
companion object {
const val TYPE_NORMAL = 100
const val TYPE_HEAD = 101
const val TYPE_LOAD_MORE = 102
}
init {
//监听recylerview的滑动
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy <= 0) {
return
}
if (loadMoreComplete && canLoadMore && !isLoading) {
var lastVisibleItem = 0
val layoutManager = recyclerView.layoutManager
if (layoutManager is LinearLayoutManager) {
lastVisibleItem = layoutManager.findLastVisibleItemPosition()
} else if (layoutManager is GridLayoutManager) {
lastVisibleItem = layoutManager.findLastVisibleItemPosition()
} else if (layoutManager is StaggeredGridLayoutManager) {
if (lastPositions == null) {
lastPositions = IntArray(layoutManager.spanCount)
}
layoutManager.findLastVisibleItemPositions(lastPositions)
lastVisibleItem = findMax(lastPositions!!)
} else {
throw RuntimeException(
"Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager"
)
}
if (lastVisibleItem + 1 == itemCount) {
loadMore()
}
}
}
})
}
}
该adapter分别可以适配线性列表,grid列表,瀑布流列表三种布局的加载更多。
使用方法:线性列表
val layoutManager = LinearLayoutManager(this); //线性布局
recyclerview.layoutManager = layoutManager
homeAdapter = object: RVLoadMoreAdapter<String>(this@AdapterMoreLoad1Activity,recyclerview,R.layout.item_rv_txt, mDatas){
override fun convert(holder: RViewHolder, t: String, position: Int) {
holder.setText(R.id.txt,mDatas[position])
}
}
recyclerview.adapter = homeAdapter
homeAdapter!!.setOnItemClickListener(object: RVLoadMoreAdapter.OnItemClickListener{
override fun onItemClick(view: View, holder: RecyclerView.ViewHolder, position: Int) {
}
override fun onItemLongClick(
view: View,
holder: RecyclerView.ViewHolder,
position: Int
): Boolean {
return false
}
})
homeAdapter!!.setLoadingMore(object: RVLoadMoreAdapter.OnLoadingMore{
override fun onLoadMore() {
downJson(mCurrentPage+1)
}
})
在downjson是可以是接口获取数据,获取完数据需要做一些操作,如下
private fun downJson(page: Int) {
Handler().postDelayed(Runnable {
swipe_layout.isRefreshing = false
if(page == 1){
mDatas.clear()
homeAdapter!!.setLoadMoreComplete(true)
}
mCurrentPage = page
val datalist = ArrayList<String>()
if(page == 3){ //模拟滑动到最底部
for (i in 1..7){
datalist.add("RecyclerView使用$i")
}
}else{
for (i in 1..20){
datalist.add("RecyclerView使用$i")
}
}
mDatas.addAll(datalist)
if (datalist.size < 20) {
homeAdapter!!.setLoadMoreComplete(false)
}
homeAdapter!!.notifyDataSetChanged()
homeAdapter!!.Loading(false)
},1000)
}
具体操作大家可以自己分析,还是很容易理解。
这里特别注意:用grid列表的时候需要加入
layoutManager.spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (homeAdapter!!.getItemViewType(position) == RVLoadMoreAdapter.TYPE_LOAD_MORE) {
2
} else {
1
}
}
}
这样加载更多的底部布局才能跨列显示。上面的2是因为我用的是2列的grid,如果是3列就是3,以此类推。
瀑布流的时候,需要重写onViewHolderCreated的方法,解决加载更多的跨列问题,如下
homeAdapter = object: RVLoadMoreAdapter<String>(this@AdapterMoreLoad3Activity,recyclerview,R.layout.item_rv_txt, mDatas){
override fun onViewHolderCreated(holder: RViewHolder, itemView: View, viewType: Int) {
super.onViewHolderCreated(holder, itemView, viewType)
if (viewType === TYPE_LOAD_MORE) {
val lp = holder.itemView.layoutParams
if (lp != null && lp is StaggeredGridLayoutManager.LayoutParams) {
lp.isFullSpan = true
}
}
}
override fun convert(holder: RViewHolder, t: String, position: Int) {
holder.setText(R.id.txt,mDatas[position])
}
}