i'm confused, how can i update my adapter views from synthetic to viewbinding!
here is my code, how define viewbinding to viewHolder?
class PlayersListAdapter(
var items: ArrayList<MatchPlayer>
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflate: View =
LayoutInflater.from(parent.context)
.inflate(R.layout.item_team_player, parent, false)
return MatchSubstitutionHolder(inflate)
}
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
viewHolder.itemView.lblPlayerName.text = "name"
}
class MatchSubstitutionHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var view = itemView
}
override fun getItemCount(): Int {
return items.size
}
}
it's so easy like define viewbinding in fragment or activity
class PlayersListAdapter(
var items: ArrayList<MatchPlayer>
) :
RecyclerView.Adapter<TeamPlayersListAdapter.MatchSubstitutionHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MatchSubstitutionHolder {
val binding= ItemTeamPlayerBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return MatchSubstitutionHolder(binding)
}
override fun onBindViewHolder(viewHolder: MatchSubstitutionHolder, position: Int) {
viewHolder.binding.lblPlayerName.text = "name"
}
class MatchSubstitutionHolder(val binding: ItemTeamPlayerBinding) : RecyclerView.ViewHolder(binding.root)
override fun getItemCount(): Int {
return items.size
}}
I think this is best for you
class PlayersListAdapter(var items: ArrayList<MatchPlayer>) :
RecyclerView.Adapter<TeamPlayersListAdapter.MatchSubstitutionHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MatchSubstitutionHolder {
val binding = ItemTeamPlayerBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MatchSubstitutionHolder(binding)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(viewHolder: MatchSubstitutionHolder, position: Int) {
viewHolder.bind(position)
}
class MatchSubstitutionHolder(val binding: ItemTeamPlayerBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(position: Int) {
val matchPlayer = items[position]
binding.lblPlayerName.text = "name"
}
}
}
Related
class CustomAdapter(val itemList: Array<String>) :
RecyclerView.Adapter<CustomAdapter.MyviewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyviewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.contact_layout, parent, false)
return MyviewHolder(view)
}
override fun onBindViewHolder(holder: MyviewHolder, position: Int) {
val item = itemList[position]
holder.itemView.text=item
}
override fun getItemCount(): Int {
return itemList.size
}
class MyviewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val itemView = view.findViewById<TextView>(R.id.contactItem)
}
}
itemView it's a generic view you've to cast it
Try below code
(holder.itemView as TextView).text = item
Modify it like this:
class CustomAdapter(val itemList: Array<String>) :
RecyclerView.Adapter<CustomAdapter.MyviewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyviewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.contact_layout, parent, false)
return MyviewHolder(view)
}
override fun onBindViewHolder(holder: MyviewHolder, position: Int) {
val item = itemList[position]
(holder as MyviewHolder).bind(item)
}
override fun getItemCount(): Int {
return itemList.size
}
class MyviewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(item: String) {
val contactItemTextView = itemView.findViewById<TextView>(R.id.contactItem)
contactItemTextView.text = item
}
}
}
I am trying to implement the function onClick in the CustomAdapter into a button so that I can call an action. I want to make it so that when the user clicks on the recycler item, the onClick function calls openTopSheet() that is from MainActivity which brings down the top sheet. In essence, how can I make it so that onClick can perform a method from MainActivity? Any help would be appreciated
CustomAdapter.kt
class CustomAdapter(val modelList: List<Model>, val context: Context) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as ViewHolder).bind(modelList.get(position));
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return ViewHolder(layoutInflater.inflate(R.layout.row_item, parent, false))
}
override fun getItemCount(): Int {
return modelList.size;
}
lateinit var mClickListener: ClickListener
fun setOnItemClickListener(aClickListener: ClickListener) {
mClickListener = aClickListener
}
interface ClickListener {
fun onClick(pos: Int, aView: () -> Unit)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
var r = MainActivity()
init {
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
r.openTopSheet()
}
fun bind(model: Model): Unit {
itemView.txt.text = model.name
itemView.sub_txt.text = model.version
val id = context.resources.getIdentifier(model.name.toLowerCase(Locale.ROOT), "drawable", context.packageName)
itemView.img.setBackgroundResource(id)
}
}
}
MainActivity.kt
open class MainActivity : AppCompatActivity(), BottomSheetRecyclerViewAdapter.ListTappedListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.home_page)
}
fun openTopSheet() {
topSheetBehavior.state = TopSheetBehavior.STATE_EXPANDED
topSheetBehavior.setTopSheetCallback(object : TopSheetBehavior.TopSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float, isOpening: Boolean?) {
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
}
})
}
}
In ViewHolder:
bind(model: Model, openTopSheet: ()->Unit)
itemView.button.setOnClickListener{
openTopSheet.invoke()
}
In adapter:
class CustomAdapter(
val modelList: List<Model>,
val context: Context,
val openTopSheet: ()->Unit)
)
(holder as ViewHolder).bind(modelList.get(position), openTopSheet);
In Activity:
val adapter = CustomAdapter(listOf(), this, { openTopSheet() } )
And you need to add openTopSheet method in activity.
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 ?
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()
}
}
I have a fragment with RecyclerAdapter inside it. I want to initialize the adapter in the onCreateView method but it throws the error of "Type mismatch. Required : Context , Found : FragmentActivity" in this statement
I have no idea why the first one showed this error and the second one did not contains compile time error.
Error shown
recyclerView!!.adapter = RestaurantMenuAdapter(activity)
No Error shown
recyclerView!!.layoutManager = LinearLayoutManager(activity)
Fragment.kt
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_restaurant_menu, container, false)
recyclerView = view.findViewById(R.id.restaurant_container)
recyclerView!!.adapter = RestaurantMenuAdapter(activity)
recyclerView!!.layoutManager = LinearLayoutManager(activity)
RecyclerAdapter.kt
class RestaurantMenuAdapter (val context : Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = parent.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.item_menu1, parent, false)) {
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return 10
}
}
Change this to-:
recyclerView!!.adapter = RestaurantMenuAdapter(activity)
To-:
recyclerView!!.adapter = RestaurantMenuAdapter(activity.applicationContext)
recyclerView!!.adapter = RestaurantMenuAdapter(this)
To
recyclerView!!.adapter = RestaurantMenuAdapter(this.requireActivity())
Keep the adapter as it and just use "activity!!" where you are initializing adapter.
recyclerView.adapter = RestaurantMenuAdapter(activity!!)
Your adapter will remain same.
class RestaurantMenuAdapter (val context : Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = parent.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.item_menu1, parent, false)) {
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return 10
}
}
Change in Recycler Adapter
from Context to Activity.
class RestaurantMenuAdapter (val context : Activity) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = parent.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.item_menu1, parent, false)) {
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return 10
}
}
How can I create on click event using interface?
In my application I've created view click interface to detect clicking on adapter items into parent activity. After creating interface and method into adapter how I can use this interface to call the view listener ?
Please check this code, It's working fine for me.
First Create Adapter class.
class ChapterAdapter(private val activity: Activity, val mWords: ArrayList<Chapter>, val btnlistener: BtnClickListener) : RecyclerView.Adapter<ChapterAdapter.ViewHolder>() {
companion object {
var mClickListener: BtnClickListener? = null
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return ViewHolder(layoutInflater.inflate(R.layout.layout_capter_raw, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
mClickListener = btnlistener
val item = mWords[position]
holder.layout_chapter_name.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
if (mClickListener != null)
mClickListener?.onBtnClick(position)
}
})
}
override fun getItemCount(): Int {
return mWords.size
}
override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
override fun getItemViewType(position: Int): Int {
return super.getItemViewType(position)
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val txt_capter_name = view.txt_capter_name
}
open interface BtnClickListener {
fun onBtnClick(position: Int)
}
}
After create and declare adapter in your Activity or Fragment.
listAdapter = ChapterAdapter(activity, _arrChapterList, object : ChapterAdapter.BtnClickListener {
override fun onBtnClick(position: Int, chapter_id: String, chapter_size: String, chapter_name: String) {
toast(chapter_id + " = " + chapter_size, Toast.LENGTH_LONG)
}
})
In Kotlin the proper way doing this, is using callbacks instead of Java Interfaces. Example:
class MyAdapter(private val callback: (YourModel) -> Unit) {
override fun onBindViewHolder(holder: DataBoundViewHolder<YourModel>, position: Int) {
bind(holder.binding, items!![position])
holder.binding.executePendingBindings()
holder.binding.root.setOnClickListener { callback(binding.model) }
}
}
And create the adapter somewhere using
MyAdapter myAdapter = MyAdapter( { println{"Clicked $it"} })
Edit: Since the Asker would like to see a full working code i used the code from Sumit and replaced the Interfaces with Kotlin-Callbacks.
class ChapterAdapter(private val activity: Activity,
val mWords: ArrayList<Chapter>,
val callback: (Any) -> Unit) :
RecyclerView.Adapter<ChapterAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return ViewHolder(layoutInflater.inflate(R.layout.layout_capter_raw, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
val item = mWords[position]
holder.layout_chapter_name.setOnClickListener( callback {$it})
}
override fun getItemCount(): Int = mWords.size
override fun getItemId(position: Int): Long = super.getItemId(position)
override fun getItemViewType(position: Int): Int = super.getItemViewType(position)
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val txt_capter_name = view.txt_capter_name
}
and finally creating the Adapter
listAdapter = ChapterAdapter(activity, _arrChapterList, {
toast( "Clicked $it", Toast.LENGTH_LONG)
})
I have the same problem, and here is my solution:
package adapter
class MarketplaceListAdapter : RecyclerView.Adapter<MarketplaceListAdapter.ViewHolder> {
private val marketplaceList: ArrayList<Marketplace>
constructor(marketplaceList: ArrayList<Marketplace>) : super() {
this.marketplaceList = marketplaceList
}
private var listener: OnItemClickListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// implementation
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// implementation
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getItemCount(): Int {
return marketplaceList.size
}
fun setListener(listener: OnItemClickListener) {
this.listener = listener
}
interface OnItemClickListener {
fun onItemClick(marketplace: Marketplace)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
var tvTitle: TextView = itemView.findViewById(R.id.tvTitle)
var ivIcon: ImageView = itemView.findViewById(R.id.ivIcon)
init {
itemView.setOnClickListener(this)
}
override fun onClick(v: View) {
listener?.onItemClick(marketplaceList[adapterPosition])
}
}
}
And on my fragment:
val list = view.findViewById<RecyclerView>(R.id.list)
list?.let {
adapter?.let { adapter ->
list.adapter = adapter
adapter.setListener(object : MarketplaceListAdapter.OnItemClickListener {
override fun onItemClick(marketplace: Marketplace) {
onMarketplaceSelected(marketplace)
}
})
}
}