美文网首页
做了一个kotlin下的Recyclerview通用框架, 减少

做了一个kotlin下的Recyclerview通用框架, 减少

作者: vb12 | 来源:发表于2018-08-01 19:22 被阅读106次

    代码放在:

    https://github.com/shaopx/LiteRecyclerViewAdapter

    效果


    image.png

    实现逻辑 (一共3个kt文件)


    Adapter.kt

    /**
     * 通用 RecyclerView.Adapter类, 基本结构与普通RecyclerView.Adapter一致.
     * 内部使用一个arrayList列表变量dataItems来存储数据, 提供了addData和replace两个方法来更新数据
     * 在onCreateViewHolder中会根据viewType找到对应的viewHolder类,并创建iewHolder类实例, 如果找不到则返回一个空实现EmptyVH实例
     * 在onBindViewHolder中,交给VH实例自己进行数据绑定操作
     */
    class Adapter(val context: Context) : RecyclerView.Adapter<VH<Data>>() {
        private val dataItems = ArrayList<Data>()
    
        override fun getItemViewType(position: Int): Int {
            return dataItems[position].itemViewType
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH<Data> {
            val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
            VHList[viewType]?.let {
                return it(view) as VH<Data>
            }
            return EmptyVH(view)
        }
    
        override fun onBindViewHolder(holder: VH<Data>, position: Int) {
            holder.bind(dataItems[position], position)
        }
    
        override fun getItemCount(): Int {
            return dataItems.size
        }
    
        fun addData(list: List<Data>) {
            dataItems.addAll(list)
            notifyDataSetChanged()
        }
    
        fun replace(list: List<Data>) {
            dataItems.run {
                clear()
                addAll(list)
            }
            notifyDataSetChanged()
        }
    }
    

    Data.kt

    interface Data {
        val itemViewType: Int
    }
    open class CommonData(
            override var itemViewType: Int,
            vHConstructorFuc: (view: View)-> VH<out Data>)
        : Data {
    
        init {
            VHList.register(itemViewType, vHConstructorFuc)
        }
    }
    

    VH.kt

    
    /**
     * 自定义的RecyclerView.ViewHolder子类.主要是为了增加bind(data: Data, position: Int)方法
     */
    abstract class VH<T : Data>(itemView: View) : RecyclerView.ViewHolder(itemView) {
        abstract fun bind(data: T, position: Int)
    }
    
    /**
     * ViewHolder的注册表, 建立itemViewType与ViewHolder的对应关系
     * 存放在map中, 效率凑合
     */
    object VHList {
        private var vhs = mutableMapOf<Int, (view: View) -> VH<out Data>>()
    
        fun register(viewType: Int, vHConstructorFuc: (view: View) -> VH<out Data>) {
            vhs[viewType] = vHConstructorFuc
        }
    
        operator fun get(viewType: Int): ((view: View) -> VH<out Data>)? = vhs[viewType]
    }
    
    /**
     * 这是一个空ViewHolder实现, 只会抛出异常
     */
    class EmptyVH(itemView: View) : VH<Data>(itemView) {
        override fun bind(data: Data, position: Int) {
            TODO("not implemented")
        }
    }
    

    使用示例:


    NotSimpleListActivity.kt:

    class NotSimpleListActivity : AppCompatActivity() {
        private lateinit var adapter: Adapter
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_simple_list)
    
            recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
            adapter = Adapter(this)
            recyclerview.adapter = adapter
    
            loadOnlineData()
        }
    
        private fun loadOnlineData() {
            ApiService.get()!!
                    .getHotScreenList(mapOf("apikey" to API_KEY,  "count" to "30"))
                    .subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeBy(
                          onError ={ Log.e("NotSimpleListActivity", "error", it) },
                          onNext = {
                             adapter.addData(it!!.subjects?.map {
                                HotScreenData(it, R.layout.douban_hotscreen_item_layout,::HotScreenDataViewHolder)
                             }!!)
                          }
                    )
        }
    }
    
    /**
     * define the wrapper data
     */
    class HotScreenData(var backdata: HotScreenResult.SubjectsBean,
                        layoutId: Int,
                        funct: (view: View) -> VH<out Data>)
        : CommonData(layoutId, funct)
    
    class HotScreenDataViewHolder : VH<HotScreenData> {
        var title: TextView? = null
        var dy: TextView? = null
        var actor: TextView? = null
        var watchNum: TextView? = null
        var rating: RatingBar? = null
        var image: ImageView? = null
    
        constructor(itemView: View) : super(itemView) {
            itemView.apply {
                title = findViewById(R.id.item_hot_screen_title)
                image = findViewById(R.id.item_hot_screen_image)
                rating = findViewById(R.id.item_hot_screen_rating)
                dy = findViewById(R.id.item_hot_screen_dy)
                actor = findViewById(R.id.item_hot_screen_actor)
                watchNum = findViewById(R.id.item_hot_screen_watch_num)
            }
        }
    
        override fun bind(data: HotScreenData, position: Int) {
            title?.text = data.backdata.title
            Glide.with(itemView.context).load(data.backdata.images?.small).into(image!!)
            rating?.rating = (data.backdata.rating?.average!! / 2).toFloat()
            dy?.text = "导演:" + data.backdata.directors!![0].name
            watchNum?.text = "${data.backdata.collect_count} 人看过"
            actor?.text = "主演:" + data.backdata.casts!!.map { it.name }
        }
    }
    

    这段代码就实现了本篇头部的效果截图.

    总结


    这个框架(实在想不出该用什么词表示了)最大的好处是数据与现实元素的聚合, 对于页面显示复杂的应用, 可以方便的添加recyclerview中的显示类型(viewType), 避免了大量if/when判断分支.
    实现简单, 只有3个kt文件.
    代码无侵入性, 非常接近原生的使用方式;

    所有的viewHolder都与数据相对应, 高聚合, 且代码更清爽.

    相关文章

      网友评论

          本文标题:做了一个kotlin下的Recyclerview通用框架, 减少

          本文链接:https://www.haomeiwen.com/subject/jcorvftx.html