Two Way Databinding For Spinner Selected Item - android

I have a view Model which has a field district which is the type of MutableLiveData<String> I have initialized it with var district = MutableLiveData<String>("") I want to bind the selected item to it for that i have a BindingClass
object SpinnerBindingUtil {
#BindingAdapter(value = ["selectedValue", "selectedValueAttrChanged"], requireAll = false)
fun bindSpinnerData(
pAppCompatSpinner: Spinner,
newSelectedValue: String,
newTextAttrChanged: InverseBindingListener
) {
pAppCompatSpinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View,
position: Int,
id: Long
) {
newTextAttrChanged.onChange()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
if (newSelectedValue != null) {
val pos =
(pAppCompatSpinner.adapter as ArrayAdapter<String?>).getPosition(
newSelectedValue
)
pAppCompatSpinner.setSelection(pos, true)
}
}
#InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged")
fun captureSelectedValue(pAppCompatSpinner: AppCompatSpinner): String {
return pAppCompatSpinner.selectedItem as String
}
}
and here is my xml
<Spinner
selectedValue="#=
{addConsumerViewModel.district}"
android:entries="#array/districts"
android:id="#+id/districtSpinner"
style="#style/AddConsumerSpinner"/>
but i am getting error how can i solve this

In kotlin you have to use kapt to working with data binding properly. In your module level build.gradle apply this plugin.
apply plugin: 'kotlin-kapt'
After that you probably face error: expected type issues. Then make your binding adapter like simple kt file by removing object SpinnerBindingUtil {}:
#BindingAdapter(value = ["selectedValue", "selectedValueAttrChanged"], requireAll = false)
fun bindSpinnerData(
pAppCompatSpinner: Spinner,
newSelectedValue: String,
newTextAttrChanged: InverseBindingListener
) {
pAppCompatSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View,
position: Int,
id: Long
) {
newTextAttrChanged.onChange()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
if (newSelectedValue != null) {
val pos =
(pAppCompatSpinner.adapter as ArrayAdapter<String?>).getPosition(
newSelectedValue
)
pAppCompatSpinner.setSelection(pos, true)
}
}
#InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged")
fun captureSelectedValue(pAppCompatSpinner: AppCompatSpinner): String {
return pAppCompatSpinner.selectedItem as String
}

Related

Android spinner item cannot be selected when not creating from resource

I am using kotlin and android 8.0, I have 2 spinners in my code, 1 of them was created using a string array from resource and another was created with an ArrayList. For the spinner that was created with an ArrayList, when clicking on the item, it does not run the OnItemSelected function and does not update the spinner.
Here is my kotlin code for the spinner
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val modules = ArrayList<Module>()
val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code)))
var line = bufferedReader.readLine()
while(line != null) {
val values = line.split(",")
modules.add(Module(values[0].replace("\uFEFF", "").toInt(), values[1], values[2].replace("\uFEFF", "").toDouble()))
line = bufferedReader.readLine()
}
val moduleCodeArray = ArrayList<String>()
val yearSpinner: Spinner = findViewById(R.id.year)
yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
moduleCodeArray.clear()
for(module in modules) {
if(module.year == position + 1) {
moduleCodeArray.add(module.moduleCode)
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
ArrayAdapter.createFromResource(
this,
R.array.years,
R.layout.custom_spinner
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
yearSpinner.adapter = adapter
}
println(moduleCodeArray)
val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code)
moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
ArrayAdapter(
this,
R.layout.custom_spinner,
moduleCodeArray
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
moduleCodeSpinner.adapter = adapter
}
}
}
EDIT: I have fixed the problem! In the code I provided, you can see my ArrayList being filled in an onItemSelected function, for some reason, the ArrayAdapter has to be in that function as well, so the correct code should look something like this.
val modules = ArrayList<Module>()
val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code)))
var line = bufferedReader.readLine()
while(line != null) {
val values = line.split(",")
modules.add(Module(values[0].replace("\uFEFF", "").toInt(), values[1], values[2].replace("\uFEFF", "").toDouble()))
line = bufferedReader.readLine()
}
val moduleCodeArray = ArrayList<String>()
val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code)
val yearSpinner: Spinner = findViewById(R.id.year)
yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
moduleCodeArray.clear()
for(module in modules) {
if(module.year == position + 1) {
moduleCodeArray.add(module.moduleCode)
}
}
ArrayAdapter(
applicationContext,
R.layout.custom_spinner,
moduleCodeArray
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
moduleCodeSpinner.adapter = adapter
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
ArrayAdapter.createFromResource(
this,
R.array.years,
R.layout.custom_spinner
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
yearSpinner.adapter = adapter
}
moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
Your Code Seems correct , I have used the same code provided by you and it worked correctly.
May you have error in custom_spinner or custom_spinner_dropdown !![You can share these layouts ]
This is what I have done:
spinner example

Android Kotlin RecyclerView Search Item with EditText with data from Data Class

So I have a RecyclerView which data is populated with data from some Data Class. I want to Apply a search item function for this recyclerview. Back when I don't use Data Classes, I followed this tutorial (The tutorial is in Java).
Now that I'm using a data class since I fetch the data that populate the recyclerview from an API endpoint, I'm quite confused on how to apply the search function in the current recyclerview.
(I fetch the data using library Retrofit if you wondering.)
This is the code snippet from the fragment:
RefundListFragment.kt
private fun fetchRefundListData() {
NetworkConfig().getRefundListDetailService().getRefundList().enqueue(object :
Callback<RefundListPOJODataClass> {
override fun onFailure(call: Call<RefundListPOJODataClass>, t: Throwable) {
...
...
...
}
override fun onResponse(
call: Call<RefundListPOJODataClass>,
response: Response<RefundListPOJODataClass>
) {
binding.refundProgressBar.visibility = View.GONE
binding.rvRefundList.adapter =
response.body()?.let { RefundListAdapter(it, this#RefundListFragment) }
fun filterString(text: String) {
val filteredList: List<RefundListPOJODataClass> = ArrayList()
for (item in response.body()?.data!!) {
if (item != null) {
if (item.buyerName?.toLowerCase()?.contains(text.toLowerCase())!!) {
filteredList.add(item)
}
}
}
adapter.filterList(filteredList)
}
binding.refundListSearchBar.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
filterString(s.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
}
})
}
However it returned an error:
Unresolved reference: add
This is the recyclerview Adapter:
RefundListAdapter.kt
class RefundListItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val refundedOrderId: TextView = itemView.refundedOrderId
private val orderDateTime: TextView = itemView.orderDateTime
private val refundedCustomerName: TextView = itemView.refundedCustomerName
fun bind(
refundHistory: RefundListPOJODataClassDataItem,
clickListener: RefundListOnItemClickListener
) {
refundedOrderId.text = refundHistory.orderId
orderDateTime.text = refundHistory.orderDate
refundedCustomerName.text = refundHistory.buyerName
itemView.setOnClickListener {
clickListener.onItemClicked(refundHistory)
}
}
}
class RefundListAdapter(
private var refundList: RefundListPOJODataClass,
private val itemClickListener: RefundListOnItemClickListener
) : RecyclerView.Adapter<RefundListItemHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RefundListItemHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.refund_list_item_layout, parent, false)
return RefundListItemHolder(v)
}
override fun getItemCount(): Int {
if (refundList.data != null) {
return refundList.data!!.size
} else {
return 0
}
}
override fun onBindViewHolder(holder: RefundListItemHolder, position: Int) {
val refundHistory = refundList.data?.get(position)
if (refundHistory != null) {
holder.bind(refundHistory, itemClickListener)
}
}
fun filterList(filteredList: List<RefundListPOJODataClass>) { //This is the function I called in the fragment
refundList = filteredList.get(0)
notifyDataSetChanged()
}
}
interface RefundListOnItemClickListener {
fun onItemClicked(refundHistory: RefundListPOJODataClassDataItem)
}
And this is how the data class looks like
RefundListPOJODataClass.kt
data class RefundListPOJODataClass(
#field:SerializedName("data")
val data: List<RefundListPOJODataClassDataItem?>? = null,
#field:SerializedName("error")
val error: Error? = null
)
data class RefundListPOJODataClassError(
#field:SerializedName("msg")
val msg: String? = null,
#field:SerializedName("code")
val code: Int? = null,
#field:SerializedName("status")
val status: Boolean? = null
)
data class RefundListPOJODataClassDataItem(
#field:SerializedName("order_date")
val orderDate: String? = null,
#field:SerializedName("buyer_name")
val buyerName: String? = null,
#field:SerializedName("phone_number")
val phoneNumber: String? = null,
#field:SerializedName("status_refund")
val statusRefund: String? = null,
#field:SerializedName("order_id")
val orderId: String? = null,
#field:SerializedName("refund")
val refund: Int? = null,
#field:SerializedName("refund_date")
val refundDate: String? = null
)
I want to search the recyclerview item by the attribute buyerName. How can I achieve it ? What should i change in my code? If there's any detail I missed to tell, Just let me know.
Your filtered list is of type List, which is immutable.
Change it to array list or MutableList:
val filteredList: ArrayList<RefundListPOJODataClass> = ArrayList()

problem populate spinner android kotlin with room database

I want to populate spinner with room database in kotlin but items in spinner are different. the number of items are true. exactly I want to make ArrayList of title in Category Class and show them in spinner in a fragment
#Entity(tableName = "cat_table")
class Category(val title: String,
val fulType: Int,
val SaleP: Long,
val BuyP: Long,
var created: Date = Date()
) {
#PrimaryKey(autoGenerate = true)
var id: Int = 0
}`
by this an want to show all title in ArrayList and set to spinner
private fun initData() {
val packageTypesAdapter = context?.let {ArrayAdapter<Any>(it,android.R.layout.simple_spinner_item)}
catViewModel!!.allCats.observe(viewLifecycleOwner, Observer { packageTypes ->
packageTypes?.forEach {packageTypesAdapter!!.add(it)}
})
spinner2.adapter = packageTypesAdapter
spinner2.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
Toast.makeText(context, "$packageTypesAdapter", Toast.LENGTH_SHORT).show()
//if (i == 0) {
// loadAllTodos()
//} else {
// val string: String = parent.getItemAtPosition(position).toString()
// loadFilteredTodos(string)
//}
}
override fun onNothingSelected(adapterView: AdapterView<*>) {
}
}
}`
if use this query
#get:Query("SELECT * FROM cat_table WHERE title ")
val allCatTitle: LiveData<List<Category>>
spinner nothing to show and below query are like this picture
#get:Query("SELECT * FROM cat_table ORDER BY created DESC")
val allCatByDate: LiveData<List<Category>>
Please check the photo
In case someone else bumps into the same issue. Here's how I did it a while ago (Kotlin).
Dao
#Query("SELECT deviceName FROM device_table WHERE deviceType = :deviceType")
fun getDevice(deviceType: String): LiveData<List<String>>
Repository
fun getDevice(deviceType: String): LiveData<List<String>> {
return deviceDao.getDevice(deviceType)
}
ViewModel
fun getDevice(deviceType: String): LiveData<List<String>> {
return repository.getDevice(deviceType)
}
And finally in my fragment:
private fun initSpinnerData() {
val spinner3 = view?.findViewById<Spinner>(R.id.spinnerRecord_devices)
if (spinner3 != null) {
val allDevices = context?.let {
ArrayAdapter<Any>(it, R.layout.spinner_text)
}
mDevicesViewModel.getDevice("Appliance")
.observe(viewLifecycleOwner, { devices ->
devices?.forEach {
allDevices?.add(it)
}
})
spinner3.adapter = allDevices
spinner3.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
Toast.makeText(requireContext(), "$allDevices", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
}
}
}

How to implement HeaderItems in Recyclerview using Groupie in Android

I am trying to use Groupie to create a recyclerview with HeaderItems. I have Group of Data like this
class Group(
val id: String = generateId(),
val name: String? = null,
val entries: List<Entry>? = null
) : Item(), Parcelable {
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.apply {
itemView.tvGroupName.text = name
}
}
override fun getLayout() = R.layout.group_single_item
constructor(source: Parcel) : this(
source.readString(),
source.readString(),
source.createTypedArrayList(Entry.CREATOR)
)
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
writeString(id)
writeString(name)
writeTypedList(entries)
}
companion object {
private fun generateId(): String {
return UUID.randomUUID().toString()
}
#JvmField
val CREATOR: Parcelable.Creator<Group> = object : Parcelable.Creator<Group> {
override fun createFromParcel(source: Parcel): Group = Group(source)
override fun newArray(size: Int): Array<Group?> = arrayOfNulls(size)
}
}
}
Every group has a list of entries
data class Entry(val id: Long=0, val name: String) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readLong(),
parcel.readString()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeLong(id)
parcel.writeString(name)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Entry> {
override fun createFromParcel(parcel: Parcel): Entry {
return Entry(parcel)
}
override fun newArray(size: Int): Array<Entry?> {
return arrayOfNulls(size)
}
}
}
So I am trying to show a list of Groups along with their respective Entries. So I will be showing a Group with its name and the list of entries. So I thought of using Groupie for this one.
This is what I have been trying
val linearLayoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
val groups = intent.getParcelableArrayListExtra<Group>("groups")
val groupAdapter = GroupAdapter<GroupieViewHolder>().apply {
val section = Section(Group())
section.setHeader(Group())
section.addAll(groups)
this.add(section)
}
recyclerViewGroups.apply {
layoutManager = linearLayoutManager
adapter = groupAdapter
}
But I am not quite sure, how to add the Group along with its Entries. Any help would be appreciated. Thanks
First you need to create item classes for your groups (possibly header and entry).
Follow instructions in this section.
E.g. those could be:
class HeaderItem(private val groupName: String) : Item() {
//... to be implemented
}
and
class EntryItem(private val entryName: String) : Item() {
//... to be implemented
}
and then use them in your adapter (needs to be tested, I'm writing this off the top of my head):
val groupAdapter = GroupAdapter<GroupieViewHolder>().apply {
groups.forEach { group ->
val section = Section()
section.setHeader(HeaderItem(group.name))
section.addAll(group.entries.map{ it -> EntryItem(it.name) })
this.add(section)
}
}

Generic RecyclerView adapter

I want to have generic RecyclerView to be able to reuse it. In my case I have 2 models: CategoryImages and Category. While trying to add constructor() it brings the following errors. I know the second one is because it understands like both primary and secondary constructor are same.
Is it possible to do such kind of thing? If yes, then how? if no - thank you.
Here is CategoryImage:
class CategoryImage {
#SerializedName("url")
private var url: String? = null
fun getUrl(): String? {
return url
}
}
And here is Category:
class Category {
#SerializedName("_id")
var id: String? = null
#SerializedName("name")
var name: String? = null
#SerializedName("__v")
var v: Int? = null
#SerializedName("thumbnail")
var thumbnail: String? = null
}
Here is the part of RecyclerViewAdapter's constructor:
class RecyclerViewAdapter(var arrayList: ArrayList<CategoryImage>?, var fragment: Int): RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
constructor(arrayList: ArrayList<Category>, fragment: Int): this(arrayList, fragment)
}
I want to have generic RecyclerView to be able to reuse it.
That's nice intention, then why you haven't made your adapter generic?
I think you can adopt the approach outlined by Arman Chatikyan in this blog post. After applying some Kotlin magic you'll only need following lines of code in order to setup your RecyclerView:
recyclerView.setUp(users, R.layout.item_layout, {
nameText.text = it.name
surNameText.text = it.surname
})
And if you need to handle clicks on RecyclerView items:
recyclerView.setUp(users, R.layout.item_layout, {
nameText.text = it.name
surNameText.text = it.surname
}, {
toast("Clicked $name")
})
Now the adapter of the RecyclerView is generic and you are able to pass list of any models inside setup() method's first argument.
In this section I will copy-paste sources from the blog post, in order to be evade from external sources deprecation.
fun <ITEM> RecyclerView.setUp(items: List<ITEM>,
layoutResId: Int,
bindHolder: View.(ITEM) -> Unit,
itemClick: ITEM.() -> Unit = {},
manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): Kadapter<ITEM> {
return Kadapter(items, layoutResId, {
bindHolder(it)
}, {
itemClick()
}).apply {
layoutManager = manager
adapter = this
}
}
class Kadapter<ITEM>(items: List<ITEM>,
layoutResId: Int,
private val bindHolder: View.(ITEM) -> Unit)
: AbstractAdapter<ITEM>(items, layoutResId) {
private var itemClick: ITEM.() -> Unit = {}
constructor(items: List<ITEM>,
layoutResId: Int,
bindHolder: View.(ITEM) -> Unit,
itemClick: ITEM.() -> Unit = {}) : this(items, layoutResId, bindHolder) {
this.itemClick = itemClick
}
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.itemView.bindHolder(itemList[position])
}
override fun onItemClick(itemView: View, position: Int) {
itemList[position].itemClick()
}
}
abstract class AbstractAdapter<ITEM> constructor(
protected var itemList: List<ITEM>,
private val layoutResId: Int)
: RecyclerView.Adapter<AbstractAdapter.Holder>() {
override fun getItemCount() = itemList.size
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): Holder {
val view = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
return Holder(view)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val item = itemList[position]
holder.itemView.bind(item)
}
protected abstract fun onItemClick(itemView: View, position: Int)
protected open fun View.bind(item: ITEM) {
}
class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)
}
Assuming CategoryImage means a Category with image.
You can express this relationship with inheritance:
open class Category(
val name: String
)
class CategoryImage(
name: String,
val image: String
) : Category(name)
class RecyclerViewAdapter(
val arr: List<Category>,
val fragment: Int
) {
fun bind(i: Int) {
val item = arr[i]
val name: String = item.name
val image: String? = (item as? CategoryImage)?.image
}
}
Another options it to have a common interface (which removes that ugly cast):
interface CategoryLike {
val name: String
val image: String?
}
class Category(
override val name: String
) : CategoryLike {
override val image: String? = null
}
class CategoryImage(
override val name: String,
override val image: String
) : CategoryLike
class RecyclerViewAdapter(private var arr: List<CategoryLike>, var fragment: Int) {
fun bind(i: Int) {
val item = arr[i]
val name: String = item.name
val image: String? = item.image
}
}
In both cases the following works (just to see that it can be compiled):
fun testCreation() {
val cats: List<Category> = listOf()
val catImages: List<CategoryImage> = listOf()
RecyclerViewAdapter(cats, 0)
RecyclerViewAdapter(catImages, 0)
}
Tip: don't use ArrayList, List (listOf(...)) or MutableList (mutableListOf(...)) should be enough for all your needs.
Tip: try to use val as much as you can, it helps prevent mistakes.
Wish: Next time please also include some relevant parts of your code in a copy-able form (not screenshot), so we don't have to re-type it and have more context. See https://stackoverflow.com/help/mcve
One "terrible" way of doing it is to simply have 1 constructor taking an ArrayList of Objects and perform an instanceof on the objects.
Both methods have the same signature, because type parameters are not considered as different types (for Java Virtual Machine both are just ArrayLists). You also need to be aware of type erasure.
Check this repository https://github.com/shashank1800/RecyclerGenericAdapter
lateinit var adapter: RecyclerGenericAdapter<AdapterItemBinding, TestModel>
...
val clickListener = ArrayList<CallBackModel<AdapterItemBinding, TestModel>>()
clickListener.add(CallBackModel(R.id.show) { model, position, binding ->
Toast.makeText(context, "Show button clicked at $position", Toast.LENGTH_SHORT)
.show()
})
adapter = RecyclerGenericAdapter(
R.layout.adapter_item, // layout for adapter
BR.testModel, // model variable name which is in xml
clickListener // adding click listeners is optional
)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(this)
adapter.submitList(viewModel.testModelList)
Recycler adapter item R.layout.adapter_item XML.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="testModel"
type="com.packagename.model.TestModel" />
</data>
...
VERY IMPORTANT NOTE: I'm using same layout for all my screens.
//********Adapter*********
// include a template parameter T which allows Any datatype
class MainAdapter<T : Any>(var data: List<T>) : RecyclerView.Adapter<MainViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
val view = parent.inflateLayout()
return MainViewHolder(view)
}
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val item = data[position]
holder.bind(item)
}
override fun getItemCount(): Int = data.size
class MainViewHolder(private val binding: MainItemsListBinding) :
RecyclerView.ViewHolder(binding.root) {
// do the same for for bind function on Viewholder
fun <T : Any> bind(item: T) {
// Extension function see code below
binding.appInfo.mySpannedString(item)
}
}
}
//Cast Item to type
fun <T : Any> TextView.mySpannedString(item: T) {
when (item.javaClass.simpleName) {
"AaProgram" -> {
item as AaProgram
this.text = buildSpannedString {
appInfo(item.numero, item.principio)
}
}
"AppContent" -> {
item as AppContent
this.text = buildSpannedString {
appInfo(item.title, item.coment, item.footnote)
}
}
"AutoDiagnostic" -> {
item as AppContent
this.text = buildSpannedString {
appInfo(item.title, item.coment, item.footnote)
}
}
"GroupDirectory" -> {}
"ReflexionsBook" -> {}
"County" -> {}
"States" -> {}
"Towns" -> {}
}
}

Categories

Resources