目标
高易用HiDataItem
需求
将列表中不同布局的视图,拆分为多种HiDataItem,优势是低耦合和高内聚
成果展示
用法
HiAdapter2 hiAdapter = new HiAdapter2(this);
List<HiDataItem> dataList = new ArrayList<>();
dataList.add(new TopTabDataItem(new ItemData()));//顶部导航栏
dataList.add(new BannerDataItem(new ItemData()));//banner
dataList.add(new GridDataItem(new ItemData()));//运营坑位区域
dataList.add(new ActivityDataItem(new ItemData()));//活动区域
dataList.add(new ItemTabDataItem(new ItemData()));//商品tab栏
hiAdapter.addItems(dataList, false);//体现了程序的可插拔性
疑难点
1.泛型参数实例化
2.itemViewType和HiDataItem实例一一对应
架构设计
关键代码
HiDataItem.kt
abstract class HiDataItem<DATA, VH : RecyclerView.ViewHolder>(data: DATA) {
var hiAdapter: HiAdapter? = null
private var mData: DATA? = null
init {
this.mData = data
}
fun setAdapter(adapter: HiAdapter) {
this.hiAdapter = adapter
}
abstract fun onBindData(holder: VH, position: Int)
/**
* 返回该item的布局资源id
*/
open fun getItemLayoutRes(): Int {
return -1
}
/**
* 返回该item的视图view
*/
open fun getItemView(parent: ViewGroup): View? {
return null
}
/**
* 刷新列表
*/
fun refreshItem() {
if (hiAdapter != null) {
hiAdapter!!.refreshItem(this)
}
}
/**
* 从列表上删除
*/
fun removeItem() {
if (hiAdapter != null) {
hiAdapter!!.removeItem(this)
}
}
/**
* 在列表上占据几列
* 0表示撑满屏幕宽度
* 1表示在每一行n列中占据1列
* 以此类推
*/
open fun getSpanSize(): Int {
return 0
}
/**
* 该item被滑进屏幕
*/
open fun onViewAttachedToWindow(holder: VH) {
}
/**
* 该item被滑出屏幕
*/
open fun onViewDetachedFromWindow(holder: VH) {
}
}
HiAdapter
override fun getItemViewType(position: Int): Int {
if (isHeaderPosition(position)) {
return headers.keyAt(position)
}
if (isFooterPosition(position)) {
//footer位置 应计算下:position=6 headersize=1 footersize=1
val footerPosition = position - getHeaderSize() - getOriginalItemSize()
return footers.keyAt(footerPosition)
}
val itemPosition = position - headers.size()
val dataItem = dataSets.get(itemPosition)
val type = dataItem.javaClass.hashCode()
if (typeArrays.indexOfKey(type) < 0) {
typeArrays.put(type, dataItem)
}
return type
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (headers.indexOfKey(viewType) >= 0) {
val view = headers[viewType]
return object : RecyclerView.ViewHolder(view) {}
}
if (footers.indexOfKey(viewType) >= 0) {
val view = footers[viewType]
return object : RecyclerView.ViewHolder(view) {}
}
val dataItem = typeArrays.get(viewType)
var view: View? = dataItem.getItemView(parent)
if (view == null) {
val layoutRes = dataItem.getItemLayoutRes()
if (layoutRes < 0) {
RuntimeException("DataItem:" + dataItem.javaClass.name + " must override getItemView or getItemLayoutRes.")
}
view = mInflater!!.inflate(layoutRes, parent, false)
}
return createViewHolderInternal(dataItem.javaClass, view!!)
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
val layoutManager = recyclerView.layoutManager
if (layoutManager is GridLayoutManager) {
val spanCount = layoutManager.spanCount
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
if (isHeaderPosition(position) || isFooterPosition(position)) {
return spanCount //撑满屏幕
}
val itemPosition = position - getHeaderSize()
if (itemPosition < dataSets.size) {
val dataItem = dataSets.get(itemPosition)
if (dataItem != null) {
val spanSize = dataItem.getSpanSize()
return if (spanSize <= 0) spanCount else spanSize
}
}
return spanCount
}
}
}
}
private fun createViewHolderInternal(
javaClass: Class<HiDataItem<*, out RecyclerView.ViewHolder>>,
view: View
): RecyclerView.ViewHolder {
val superClass = javaClass.genericSuperclass
if (superClass is ParameterizedType) {
val arguments = superClass.actualTypeArguments
for (argument in arguments) {
if (argument is Class<*> && RecyclerView.ViewHolder::class.java.isAssignableFrom(
argument
)
) {
try {
return argument.getConstructor(View::class.java)
.newInstance(view) as RecyclerView.ViewHolder
} catch (e: Throwable) {
e.printStackTrace()
}
}
}
}
return object : RecyclerView.ViewHolder(view) {}
}