Reputation: 1752
How to do latest jetpack "View binding" in adapter, for automatically binding the views. I am not using the findVeiwById or Butterknife or Kotlin synthetic??? I have used the new view binding and is is working fine for Activity and for Fragment. I am able to see the ActivityHomeBinding and FragmentHomeBinding files after enabling the viewBinding in build.gradle file. Also, I am seeing the class ItemListBinding for the item xml used i.e. item_list.xml. But how to use this file in the adapter of the recyclerview
viewBinding {
enabled = true
}
Home Activity file
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)
}
Fragment
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentHomeBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
Base Adapter: Want to use view binding here. I am able to see ItemListBinding, but not getting how to use it.
class BaseAdapter @Inject constructor(
private val context: Context,
private val picasso: Picasso
) :
RecyclerView.Adapter<BaseAdapter.ViewHolder>() {
private var data = ArrayList<Data>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(context).inflate(R.layout.item_list, parent, false)
)
}
override fun getItemCount() = data.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder) {
// TODO
}
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
@BindView(R.id.tvMovieName)
lateinit var nameTV: TextView
@BindView(R.id.imageView)
lateinit var bannerImage: ImageView
init {
ButterKnife.bind(this@ViewHolder, view)
}
}
fun setData(serverData: ArrayList<Data>) {
data = serverData
notifyDataSetChanged()
}
}
Upvotes: 36
Views: 27562
Reputation: 1805
I use this template that also integrates with click event:
class BannerAdapter(private val listener: OnCategoryClickListener) :
ListAdapter<Banner, BannerAdapter.BannerViewHolder>(DiffCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
val binding = ItemRecyclerviewCategoriesSearchBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return BannerViewHolder(binding)
}
override fun onBindViewHolder(holder: BannerViewHolder, position: Int) {
val currentItem = getItem(position)
holder.bind(currentItem)
}
inner class BannerViewHolder(private val binding: ItemRecyclerviewCategoriesSearchBinding) :
RecyclerView.ViewHolder(binding.root) {
init {
binding.root.setOnClickListener {
val position = absoluteAdapterPosition
if (position != RecyclerView.NO_POSITION){
val banner = getItem(position)
listener.onCategoryClick(banner.link_type, banner.link)
}
}
}
fun bind(banner: Banner) {
binding.apply {
Glide.with(itemView.context)
.load(banner.media.url)
.centerCrop()
.transition(DrawableTransitionOptions.withCrossFade())
.error(R.drawable.ic_broken_image)
.into(imageCategory)
}
}
}
interface OnCategoryClickListener {
fun onCategoryClick(type: String, link: String)
}
private class DiffCallBack : DiffUtil.ItemCallback<Banner>() {
override fun areItemsTheSame(oldItem: Banner, newItem: Banner) =
oldItem == newItem
override fun areContentsTheSame(oldItem: Banner, newItem: Banner) =
oldItem.media == newItem.media
}
}
Upvotes: 1
Reputation: 2819
I found this the easiest:
class RvAdapter() :
RecyclerView.Adapter<RvAdapter.RvViewHolder>() {
inner class RvViewHolder(val binding: OtherRvItemBinding) :
RecyclerView.ViewHolder(binding.root)
// Initialise view binding here.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvViewHolder {
val binding =
OtherRvItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return RvViewHolder(binding)
}
override fun getItemCount(): Int {
// TODO: Implement logic to return list size.
return 0
}
// Bind view holder.
override fun onBindViewHolder(holder: RvViewHolder, position: Int) {
holder.binding.apply {
// Reference your views from here.
awesomeTv.text = "Hello World!"
}
}
}
Upvotes: 2
Reputation: 1324
I found the easiest way to use View Binding in the RecyclerView Adapter class
class MediaRecyclerViewAdapter: RecyclerView.Adapter<MediaRecyclerViewAdapter.MediaViewHolder>() {
lateinit var list: List<String>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaViewHolder {
val binding = CardviewItemsRecyclerviewBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return MediaViewHolder(binding)
}
override fun onBindViewHolder(holder: MediaViewHolder, position: Int) {
holder.binding.mediaHeadingTextView.text = "Hello"
}
override fun getItemCount(): Int {
return list.size
}
class MediaViewHolder(val binding: CardviewItemsRecyclerviewBinding) : RecyclerView.ViewHolder(binding.root) {
}
}
Upvotes: 4
Reputation: 81568
Nothing really changes compared to how you'd normally do it.
class DataAdapter(
private val context: Context,
private val picasso: Picasso
) : RecyclerView.Adapter<DataAdapter.ViewHolder>() {
private var dataList: List<Data> = Collections.emptyList()
override fun getItemCount() = dataList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(
LayoutInflater.from(context).inflate(R.layout.item_list, parent, false)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(dataList[position])
}
fun setData(dataList: List<Data>) {
this.dataList = dataList
notifyDataSetChanged()
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val binding = ItemListBinding.bind(view)
fun bind(data: Data) {
with(binding) {
// TODO
nameTV.text = data.name
bannerImage.loadWithPicasso(picasso, data.imageUrl)
}
}
}
}
Upvotes: 19
Reputation: 1752
Found another to resolve it
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemListBinding.inflate(LayoutInflater.from(context), parent, false)
return MovieViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder) {
with(moviesData[position]) {
binding.tvMovieName.text = title
}
}
}
}
class MovieViewHolder(val binding: ItemMovieBinding) : RecyclerView.ViewHolder(binding.root)
Upvotes: 33
Reputation: 17268
You can use static bind
method of ViewBinding to create binding from already existing layout. Add it as a property to viewholder:
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = ItemListBinding.bind(view)
}
then you can access all the views through the binding
field, for example:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder) {
// TODO
binding.tvMovieName.text = data[position].title
binding.imageView.setDrawableImage(data[position].image)
}
}
Upvotes: 67