Search code examples
androiddata-bindingandroid-listviewandroid-databinding

How to use DataBinding in a ListView?


I'm using databiding into a RecyclerView in my layout like below :

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/topup_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:items="@{viewModel.items}"
            tools:listitem="@layout/list_item_content" />

and the list and binding adapters like :

@BindingAdapter("app:items")
fun setItems(listView: RecyclerView, items: List<ListItem>?) {
    items?.let {
        (listView.adapter as MyListAdapter).submitList(items)
    }
}

//------------------

class MyListAdapter() :
    ListAdapter<ListItem, ViewHolder>(myListItemDiffCallback()) {

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder.from(parent)
    }

    class ViewHolder private constructor(private val binding: ListItemContentBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(item: ListItem) {

            binding.item = item
            binding.executePendingBindings()
        }

        companion object {

            fun from(parent: ViewGroup): ViewHolder {

                val layoutInflater = LayoutInflater.from(parent.context)
                val binding = TopUpListItemContentBinding.inflate(layoutInflater, parent, false)

                return ViewHolder(binding)
            }
        }
    }
}

class myListItemDiffCallback : DiffUtil.ItemCallback<ListItem>() {

    override fun areItemsTheSame(oldItem: ListItem, newItem: ListItem): Boolean {
        return oldItem.label == newItem.label
    }

    override fun areContentsTheSame(
        oldItem: ListItem,
        newItem: ListItem
    ): Boolean {
        return oldItem == newItem
    }
}

But it's not the same case using a simple ListView. For many reasons, I prefer using a listview and I tried but I don't know how to customize my adapter for databiding like I used in RecycleView.

Below is My adapter for Listview :

class MyListAdapter(context: Context, items: List<ListItem>) :
    ArrayAdapter<ListItem>(context, 0, items) {

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {

        val binding = ListItemContentBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )

        binding.item = getItem(position)

        return binding.root
    }
}

My Item class Model :

data class ListItem(
    val iconResId: Int,
    val label: String,
    val action: () -> Unit
)

Any one has a clue ?


Solution

  • Try to update your adapter like below:

    class MyListAdapter(context: Context, var items: List<ListItem> = arrayListOf()) :
        ArrayAdapter<ListItem>(context, 0, items) {
    
        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
    
            val binding = ListItemContentBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
    
            binding.item = items[position]
    
            return binding.root
        }
    
        override fun getCount(): Int {
            return items.size
        }
    
    
        fun submitList(items: List<ListItem>) {
            this.items = items
            notifyDataSetChanged()
        }
    }