什么?这个天天使用的 API 竟然被废弃了?,android 组件化和模块化区别
接下来创建两个非常简单的 Adapter,一个 TitleAdapter 和一个 BodyAdapter,待会我们会用 MergeAdapter 将这两个 Adapter 合并到一起。TitleAdapter 代码如下:
class?TitleAdapter(val?items:?List<String>)?:?RecyclerView.Adapter<TitleAdapter.ViewHolder>()?{
inner?class?ViewHolder(view:?View)?:?RecyclerView.ViewHolder(view)?{
val?text:?TextView?=?view.findViewById(R.id.text)
}
override?fun?onCreateViewHolder(parent:?ViewGroup,?viewType:?Int):?ViewHolder?{
val?view?=?LayoutInflater.from(parent.context).inflate(R.layout.item_view,?parent,?false)
val?holder?=?ViewHolder(view)
return?holder
}
override?fun?getItemCount()?=?items.size
override?fun?onBindViewHolder(holder:?ViewHolder,?position:?Int)?{
holder.text.text?=?items[position]
}
}
这是一个 Adapter 最简单的实现,没有任何逻辑在里面,只是为了显示一行文字。item_view 是个只包含一个 TextView 控件的简单布局,这里就不展示其中的代码了。然后 BodyAdapter 的代码如下:
class?BodyAdapter(val?items:?List<String>)?:?RecyclerView.Adapter<BodyAdapter.ViewHolder>()?{
inner?class?ViewHolder(view:?View)?:?RecyclerView.ViewHolder(view)?{
val?text:?TextView?=?view.findViewById(R.id.text)
}
override?fun?onCreateViewHolder(parent:?ViewGroup,?viewType:?Int):?ViewHolder?{
val?view?=?LayoutInflater.from(parent.context).inflate(R.layout.item_view,?parent,?false)
val?holder?=?ViewHolder(view)
return?holder
}
override?fun?getItemCount()?=?items.size
override?fun?onBindViewHolder(holder:?ViewHolder,?position:?Int)?{
holder.text.text?=?items[position]
}
}
基本上就是复制过来的代码,和 TitleAdapter 没有什么区别。然后我们在 MainActivity 当中就可以这样使用了:
class?MainActivity?:?AppCompatActivity()?{
override?fun?onCreate(savedInstanceState:?Bundle?)?{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val?titleItems?=?generateTitleItems()
val?titleAdapter?=?TitleAdapter(titleItems)
val?bodyItems?=?generateBodyItems()
val?bodyAdapter?=?BodyAdapter(bodyItems)
val?mergeAdapter?=?MergeAdapter(titleAdapter,?bodyAdapter)
recyclerView.layoutManager?=?LinearLayoutManager(this)
recyclerView.adapter?=?mergeAdapter
}
private?fun?generateTitleItems():?List<String>?{
val?list?=?ArrayList<String>()
repeat(5)?{?index?->
list.add("Title?$index")
}
return?list
}
private?fun?generateBodyItems():?List<String>?{
val?list?=?ArrayList<String>()
repeat(20)?{?index?->
list.add("Body?$index")
}
return?list
}
}
可以看到,这里我编写了 generateTitleItems()和 generateBodyItems()这两个方法,分别用于给两个 Adapter 生成数据集。然后创建了 TitleAdapter 和 BodyAdapter 的实例,并使用 MergeAdapter 将它们合并到一起。合并的方式很简单,就是将你要合并的所有 Adapter 的实例都传入到 MergeAdapter 的构造方法当中即可。最后,将 MergeAdapter 设置到 RecyclerView 当中,整个过程结束。是不是非常简单?几乎和之前 RecyclerView 的用法没有任何区别。现在运行一下程序,效果如下图所示:
可以看到,TitleAdapter 和 BodyAdapter 中的数据是合并到一起显示的,同时也就说明,我们的 MergeAdapter 已经成功生效了。到这里为止都还算很好理解,但是接下来,我要给大家一个灵魂拷问了。如果这时,我想要监听 BodyAdapter 中元素的点击事件,那么调用 getAdapterPosition()方法,获得的到底是 BodyAdapter 中元素的点击位置,还是合并之后元素的点击位置呢?你会发现,这个时候 getAdapterPosition()方法已经会造成歧义了,这也就是开篇那段英文所描述的问题。而解决办法当然也很简单,Google 废弃了 getAdapterPosition()方法,但是却又提供了 getBindingAdapterPosition()和 getAbsoluteAdapterPosition()这两个方法。从名字上就可以看出来了,一个是用于获取元素位于当前绑定 Adapter 的位置,一个是用于获取元素位于 Adapter 中的绝对位置。如果觉得我上面的解释还不够清楚,通过下面的示例看一下你立马就能明白了。我们修改 BodyAdapter 中的代码,在里面加入监听当前元素点击事件的代码,如下所示:
class?BodyAdapter(val?items:?List<String>)?:?RecyclerView.Adapter<BodyAdapter.ViewHolder>()?{
override?fun?onCreateViewHolder(parent:?ViewGroup,?viewType:?Int):?ViewHolder?{
val?view?=?LayoutInflater.from(parent.context).inflate(R.layout.item_view,?parent,?false)
val?holder?=?ViewHolder(view)
holder.itemView.setOnClickListener?{
val?position?=?holder.bindingAdapterPosition
Toast.makeText(parent.context,?"You?c
licked?body?item?$position",?Toast.LENGTH_SHORT).show()
}
return?holder
}
...
}
评论