Get multiple / dynamic EditText value in RecyclerView - android

I'm new with these case and I want to try to get the value of dynamic EditText(s) from RecyclerView.
And in the layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_marginTop="#dimen/_10sdp"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_question"
style="#style/textH4"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="bottom"
android:text="Ini adalah tempat pertanyaan pertama" />
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/et_answer"
android:layout_width="match_parent"
android:layout_height="#dimen/_120sdp"
android:hint="Tulis jawaban anda"
style="#style/EdittextPrimary"
android:gravity="top"
android:background="#drawable/bg_outline_grey"
android:inputType="textMultiLine"
android:layout_marginTop="#dimen/_10sdp"/>
</LinearLayout>
The question is.. how do I get the EditText value and put it in an ArrayList ?
Newest update codes :
I add my Recycler Adapter, and tried these :
class RequestJoinAdapter(
val onTextChanged: (text:String,position:Int)->Unit
) :
RecyclerView.Adapter<RequestJoinAdapter.ViewHolder>() {
var listData: MutableList<KeamananModel> = ArrayList()
private var textValue = ""
fun insertAll(data: List<KeamananModel>) {
data.forEach {
listData.add(it)
notifyItemInserted(listData.size - 1)
}
}
fun clear() {
if (listData.isNotEmpty()) {
listData.clear()
notifyDataSetChanged()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
ItemRequestJoinBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = listData[position]
holder.bindTo(item)
holder.binding.etAnswer.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable?) {
onTextChanged.invoke(s.toString(), position)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
textValue = s.toString().toLowerCase()
}
})
}
override fun getItemCount() = listData.size
inner class ViewHolder(val binding: ItemRequestJoinBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindTo(item: KeamananModel) {
val context = binding.root.context
binding.tvQuestion.text = item.qt
}
}
private fun isLog(msg: String) {
Log.e("join grup:", msg)
}
}
and in my current Activity, I used to add some codes like
RequestJoinAdapter { text, position ->
val values = ArrayList<Jawaban>()
val hashSet = HashSet<Jawaban>()
values.add(Jawaban(pertanyaan_no = position+1, jawaban = text))
hashSet.addAll(values)
values.clear()
values.addAll(hashSet)
val valuest = ArrayList<JawabanKeamanan>()
val hashSets = HashSet<JawabanKeamanan>()
valuest.add(JawabanKeamanan(values))
hashSets.addAll(valuest)
valuest.clear()
valuest.addAll(hashSets)
isLog("currentResult: $valuest")
}
How do I set my latest valuest into my var listJawaban: MutableList<JawabanKeamanan> = ArrayList() without any duplicate datas inside it ? What I want is like JawabanKeamanan(jawaban_keamanan=[Jawaban(pertanyaan_no=1, jawaban=t)], [Jawaban(pertanyaan_no=2, jawaban=u)]). Thanks..

The simplest answer is to implement a TextWatcher to your EditText and have it return your data when your text is changed.
Now you may ask how can I get such data in my activty? Well it's pretty simple.
Create an interface in your adapter to communicate with your activity.
Pass your interface as a constructor parameter so when you initialize your adapter in the activity your methods are implemented.
Another solution for you is to add a button in each item of your list and call your interface method in the button's OnClickListener.
EDIT:
In the snippet below I have used a lambda function for when the text changes.
class RequestJoinAdapter(
private val onClickedItem: (ArrayList<String>)->Unit,
val onTextChanged: (text:String,position:Int)->Unit
):
RecyclerView.Adapter<RequestJoinAdapter.ViewHolder>() {
var listData: MutableList<KeamananModel> = ArrayList()
var listJawaban: MutableList<Jawaban> = ArrayList()
private var textValue = ""
fun insertAll(data: List<KeamananModel>) {
data.forEach {
listData.add(it)
notifyItemInserted(listData.size - 1)
}
}
fun clear() {
if (listData.isNotEmpty()) {
listData.clear()
notifyDataSetChanged()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
ItemRequestJoinBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = listData[position]
holder.bindTo(item)
}
override fun getItemCount() = listData.size
inner class ViewHolder(val binding: ItemRequestJoinBinding):
RecyclerView.ViewHolder(binding.root) {
fun bindTo(item: KeamananModel) {
val context = binding.root.context
binding.tvQuestion.text = item.qt
binding.etAnswer.addTextChangedListener(object: TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable?) {
if (textValue.isNotEmpty()) {
isLog(textValue)
onTextChanged.invoke(s,absoluteAdapterPosition)
} else {
}
listJawaban.add(Jawaban(pertanyaan_no = adapterPosition + 1, jawaban = textValue))
isLog(listJawaban.toString())
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
textValue = s.toString().toLowerCase()
}
})
}
}
private fun isLog(msg: String) {
Log.e("join grup:", msg)
}
}
Pay attention to the onTextChanged.invoke() method. This lambda function can be used like an interface to communicate between your adapter and your view. It will be triggered every time your text is changed.
Finally instantiate your adapter like below:
val adapter = RequestJoinAdapter({
}, { text, position ->
//onTextChanged
})
The position argument is there to help you know which TextView was changed

Related

How to display an empty item of recyclerview so that user can fill the data into it?

I am new to kotlin-android and I am developing a stock keeping unit, where in one fragment i need to load the data into recycler view using arraylist but also, i need one blank item, where user can enter his own data and once he fills that blank item, a new blank item should be created.
class RecyclerViewAdapterU (val dataList:ArrayList<ModelClass>): RecyclerView.Adapter<RecyclerViewAdapterU.ViewHolder>() {
var _binding: UploadItemViewBinding? = null
val binding get() = _binding!!
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerViewAdapterU.ViewHolder {
val v =
LayoutInflater.from(parent.context).inflate(R.layout.upload_item_view, parent, false)
_binding = UploadItemViewBinding.bind(v)
return ViewHolder(binding.root)
}
fun getUpdatedDetails(skucode:String,pos:Int){
// val skuDetails:ArrayList<ModelClass>
val call: Call<List<ModelClass>>? =
ApiClient.instance?.myApi?.getfromsku(skucode)!!
call!!.enqueue(object : Callback<List<ModelClass>?> {
override fun onResponse(
call: Call<List<ModelClass>?>,
response: Response<List<ModelClass>?>
) {
if (!response.body().isNullOrEmpty()) {
val skuDetails: ArrayList<ModelClass> = response.body() as ArrayList<ModelClass>
//
// if (!skuDetails.isNullOrEmpty()) {
val x = dataList[pos].sku_code
if (skuDetails[pos].sku_code != x) {
//for (i in skuDetails.indices){
println(skuDetails[pos].sku_code)
println(".........$pos")
dataList.removeAt(pos)
dataList.add(pos, skuDetails[0])
skuDetails.clear()
notifyItemChanged(pos)
//}
}
}
}
override fun onFailure(call: Call<List<ModelClass>?>, t: Throwable) {
}
})
}
override fun onBindViewHolder(holder: ViewHolder, #SuppressLint("RecyclerView") position: Int) {
bindItems(dataList[position])
holder.getStock()
holder.updateStockDetail()
}
fun bindItems(data: ModelClass) {
binding.apply {
itemquant.text=data.item_quant
uploadItemName.text = data.item_name
uploadMfg.text = data.mfg
skuStock.setText(data.item_stock.toString())
skuCode.setText(data.sku_code)
}
}
override fun getItemCount(): Int {
return dataList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun getStock() {
binding.skuStock.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
if (binding.skuStock.isFocused){
for (i in 0 until RecyclerViewAdapter.ob.dataSelected.size){
if (editable.toString().trim()!=""){
var x= editable.toString().trim().toInt()
RecyclerViewAdapter.ob.dataSelected[adapterPosition].item_stock=x
//getting current itemstock before pushing update.
//assigning latest itemstock to the data for the update
}
}
}}
})
}
fun updateStockDetail(){
binding.skuCode.addTextChangedListener(object : TextWatcher{
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
}
override fun afterTextChanged(editable: Editable) {
//binding.skuCode.removeTextChangedListener(this)
var pos:Int=adapterPosition
var x= editable.toString().trim()
//RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code=x
println("$x in textwatcher and $pos")
//getting edited text and calling the function to get updated details.
getUpdatedDetails(x,pos)
// binding.skuCode.addTextChangedListener(this)
}
})
}
}
}
I have couple of bugs in the adapter too, for example, i cant change textwatcher more than once.
If somebody could help me with this, would be very glad.
ob.data.selected comes from another recyclerview adapter.
One way you can do this is by using a different view type for the blank item that will always stay at the very top (or bottom if you prefer). Once the blank item is filled up then a new non-blank item with a different view type will be added to your list.
More info about view types here: Android and Kotlin: RecyclerView with multiple view types

Another "RecyclerView duplicating items" question

I'm having this problem and spent hours exploring different solutions found here but couldn't figure it out. I have a RecyclerView with a RadioGroup (with two RadioButton) and an EditText. As expected, the text keeps getting duplicated on scroll and the "original" gets deleted. The same happens with the radio buttons. I've tried to save on another array backup the values when the view is recycled but couldn't solve the duplicating issue.
Here's my adapter
class ServicesCheckoutAdapter(var context: Context,
var servicesList: List<Service>) : RecyclerView.Adapter<ServicesCheckoutAdapter.ViewHolder>() {
private lateinit var onRadioGroupClickListener: OnRadioGroupClickListener
private lateinit var onTextChangedListener: OnTextChangedListener
private lateinit var onServiceClickListener: OnServiceClickListener
private var externalArray = mutableListOf<String>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.services_list_item,
parent, false)
val viewHolder = ViewHolder(view)
val position = viewHolder.adapterPosition
view.setOnClickListener {
if (onServiceClickListener != null) {
onServiceClickListener.onServiceClick(view, servicesList[position].id, position)
}
}
return viewHolder
}
override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
override fun getItemViewType(position: Int): Int {
return super.getItemViewType(position)
}
interface OnServiceClickListener {
fun onServiceClick(view: View, serviceId: Int, position: Int)
}
fun setOnServiceClickListener(listener: OnServiceClickListener)
{
onServiceClickListener = listener
}
interface OnRadioGroupClickListener {
fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {}
}
fun setOnRadioButtonClickListener(listener: OnRadioGroupClickListener) {
onRadioGroupClickListener = listener
}
interface OnTextChangedListener{
fun onTextChanged(position: Int, text: String)
}
fun setOnTextChangedListener(listener: OnTextChangedListener){
onTextChangedListener = listener
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d("recycler", "lista: ${servicesList[position].serviceSolution}")
holder.edtSolution.removeTextChangedListener(holder.watcher)
holder.bind(context,
servicesList[position].id,
servicesList[position].name,
servicesList[position].serviceSolved,
servicesList[position].serviceSolution,
onRadioGroupClickListener,
onTextChangedListener,
position)
}
override fun getItemCount(): Int {
return servicesList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var radioGroup = itemView.findViewById<RadioGroup>(R.id.radioGroupService)
val edtSolution = itemView.findViewById<EditText>(R.id.editTextCheckoutDesc)
var watcher: TextWatcher? = null
fun bind(context: Context,
serviceId: Int,
serviceName: String,
serviceSolved: Boolean,
serviceSolution: String,
onRadioGroupClickListener: OnRadioGroupClickListener,
onTextChangedListener: OnTextChangedListener,
position: Int
) {
itemView.findViewById<TextView>(R.id.serviceTitle)
.text = context.resources
.getString(R.string.service_title_comma, serviceName)
itemView.findViewById<RadioGroup>(R.id.radioGroupService)
.setOnClickListener {
onRadioGroupClickListener
.onRadioGroupClick(
(it as RadioGroup).checkedRadioButtonId, serviceId, adapterPosition)
}
if (serviceSolved) {
radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = true
radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = false
} else {
radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = false
radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = true
}
edtSolution.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChangedListener.onTextChanged(position, s.toString())
}
override fun afterTextChanged(s: Editable?) {
}
})
}
}
}
And here's the adapter initialization on the activity
serviceList = occurrence.services
servicesAdapter = ServicesCheckoutAdapter(this, serviceList)
recyclerViewServices.adapter = servicesAdapter
recyclerViewServices.layoutManager = LinearLayoutManager(this)
servicesAdapter.setOnRadioButtonClickListener(object : ServicesCheckoutAdapter.OnRadioGroupClickListener {
override fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {
super.onRadioGroupClick(buttonId, serviceId, position)
when (buttonId) {
R.id.radioBtnYes -> {
serviceList[position].serviceSolved = true
servicesAdapter.notifyDataSetChanged()
}
R.id.radioBtnNo -> {
serviceList[position].serviceSolved = false
servicesAdapter.notifyDataSetChanged()
}
}
}
})
servicesAdapter.setOnTextChangedListener(object : ServicesCheckoutAdapter.OnTextChangedListener{
override fun onTextChanged(position: Int, text: String) {
serviceList[position].serviceSolution = text
}
})
RecyclerView isn't usually made for Input views. As Android saves the input of a view depending on its ID, your RecyclerView has X number of views that all have the same ID, hence they all use the same state.
A solution to this would be saving your input state manually in recycle method, and restoring it in bind method.
So if you have 20 items, you have 20 states. Initially they are all empty or defaulted, and change when needed to save.
A more simpler approach would be using a LinearLayout or similar Layouts to accomplish your goal, but that depends on how many items you have and how many views that will contain.
You still need to be careful for the View ID part, though
I've tried to use a ListView but the keyboard went crazy changing focus. Decided to keep the RecyclerView and since my dynamic list isn't so large, I used the
holder.setIsRecyclable(false);
on the OnBindViewHolder() method and it solved my issue. Thanks everyone for the help

Saving EditText content in RecyclerView on Kotlin

Similarly to Saving EditText content in RecyclerView, I have an implementation of a pair of EditTexts to fill inside every row of a RecyclerView. But my position variable inside my TextWatcher is always returning 0, even after the updatePosition function been called.
the Lod.d at afterTextChanged() on both Watchers always shows that position is 0, even after filling the editText at the 3rd position.
I can see that updatePosition goes from 0 to areasimportadas.size during the onBindViewHolder function, but it doesn't happen for onTextChanged.
class importItemsAdapter(val areasImportadas: MutableList, val inclinaLida: MutableList, val desvLido: MutableList) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.import_items,parent,false)
return CustomViewHolder(cellForRow)
}
override fun getItemCount(): Int {
return areasImportadas.size
}
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
holder.itemView.importNum.text = (position+1).toString()
holder.itemView.importArea.text = areasImportadas[position]
Watcher1().updatePosition(holder.adapterPosition)
Watcher2().updatePosition(holder.adapterPosition)
holder.itemView.importInclina.addTextChangedListener(Watcher1())
holder.itemView.importDesv.addTextChangedListener(Watcher2())
}
class CustomViewHolder(view: View): RecyclerView.ViewHolder(view)
private inner class Watcher1 : TextWatcher {
var position = 0
fun updatePosition(positionExt: Int) {
this.position = positionExt
Log.d("Registro", this.position.toString())
}
override fun afterTextChanged(arg0: Editable) {
inclinaLida[position]= arg0.toString()
Log.d("Registro", "Inclinação $position: ${inclinaLida[position]}")
}
override fun beforeTextChanged(arg0: CharSequence, arg1: Int, arg2: Int, arg3: Int) {}
override fun onTextChanged(s: CharSequence, a: Int, b: Int, c: Int) {
}
}
private inner class Watcher2 : TextWatcher {
var position = 0
fun updatePosition(positionExt: Int) {
position = positionExt
Log.d("Registro", position.toString())
}
override fun afterTextChanged(arg0: Editable) {
Log.d("Registro", "Desvio ${position}: ${desvLido[position]}")
}
override fun beforeTextChanged(arg0: CharSequence, arg1: Int, arg2: Int, arg3: Int) {
}
override fun onTextChanged(s: CharSequence, a: Int, b: Int, c: Int) {
desvLido[position]=s.toString()
}
}
}
I needed to be able to store each EditText content under its proper position on both lists (desvLido and inclinaLida)
What was missing was calling an instance:
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
holder.itemView.importNum.text = (position+1).toString()
holder.itemView.importArea.text = areasImportadas[position]
val watcher1 = Watcher1()
watcher1.updatePosition(holder.adapterPosition)
holder.itemView.importInclina.addTextChangedListener(watcher1)
}
Now position returns the correct value.

Detecting click for Recyclerview inside RecyclerView

I have implemented a recyclerview within recyclerview. Here is my code
activity_main
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/rv_activity_main"
app:layoutManager="android.support.v7.widget.GridLayoutManager"
app:spanCount="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private var graduationList = ArrayList<Graduation>()
private var yearList = ArrayList<YearList>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initList()
rv_activity_main.adapter = MainAdapter(graduationList)
}
private fun initList(){
graduationList.clear()
yearList.clear()
yearList.add(YearList("2011"))
yearList.add(YearList("2012"))
yearList.add(YearList("2013"))
yearList.add(YearList("2014"))
yearList.add(YearList("2015"))
yearList.add(YearList("2016"))
yearList.add(YearList("2017"))
yearList.add(YearList("2018"))
yearList.add(YearList("2019"))
graduationList.add(Graduation("UG",yearList))
graduationList.add(Graduation("PG",yearList))
}
}
Graduation Pojo Class
data class Graduation(
var name: String,
var yearList: ArrayList<YearList>
)
YearList Pojo Class
data class YearList(var yearName: String)
MainAdapter
class MainAdapter(private var graduationList: ArrayList<Graduation>): RecyclerView.Adapter<MainAdapter.MainViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): MainViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.cell_main_adapter,p0,false)
return MainViewHolder(itemView)
}
override fun getItemCount(): Int {
return graduationList.size
}
override fun onBindViewHolder(p0: MainViewHolder, p1: Int) {
p0.graduationTextView.text = graduationList[p1].name
p0.graduationRecyclerView.adapter = SecondAdapter(graduationList[p1].yearList)
}
inner class MainViewHolder(view: View): RecyclerView.ViewHolder(view){
var graduationTextView: TextView = view.findViewById(R.id.tv_cell_main_adapter)
var graduationRecyclerView: RecyclerView = view.findViewById(R.id.rv_cell_main_adapter)
}
}
SecondAdapter
class SecondAdapter(private var yearList: ArrayList<YearList>): RecyclerView.Adapter<SecondAdapter.SecondViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): SecondViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.cell_second_adapter,p0,false)
return SecondViewHolder(itemView)
}
override fun getItemCount(): Int {
return yearList.size
}
override fun onBindViewHolder(p0: SecondViewHolder, p1: Int) {
p0.yearTextView.text = yearList[p1].yearName
p0.itemView.setOnClickListener {
Log.i("Pritish",yearList[p1].yearName+"\n")
}
}
inner class SecondViewHolder(view: View): RecyclerView.ViewHolder(view){
var yearTextView: TextView = view.findViewById(R.id.tv_cell_year_title)
}
}
ItemClick for MainAdapter should not be clickable so I have not added any itemClick for it. Suppose user clicks a particular year I know which year the user selected but my question is, how to know when a year is clicked whether it's from UG or PG without implementing a itemclick listener for MainAdapter?
Try this way,
Pass Graduation object in SecondAdapter constuctor from MainAdapter like below.
p0.graduationRecyclerView.adapter = SecondAdapter(graduationList[p1])
Second Adapter
class SecondAdapter(private var graduation: Graduation): RecyclerView.Adapter<SecondAdapter.SecondViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): SecondViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.cell_second_adapter,p0,false)
return SecondViewHolder(itemView)
}
override fun getItemCount(): Int {
return graduation.yearList.size
}
override fun onBindViewHolder(p0: SecondViewHolder, p1: Int) {
p0.yearTextView.text = graduation.yearList[p1].yearName
p0.itemView.setOnClickListener {
Log.i("Pritish",graduation.yearList[p1].yearName+" "+graduation.name+"\n")
}
}
inner class SecondViewHolder(view: View): RecyclerView.ViewHolder(view){
var yearTextView: TextView = view.findViewById(R.id.tv_cell_year_title)
}
}

setOnLongClickListener in android with kotlin

How can I use setOnItemClickListner in each item in my ListView?
my xml :
<ListView
android:id="#+id/tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
this my adapter class
inner class mo3d1Adapter : BaseAdapter {
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getCount(): Int {
return listOfmo3d.size
}
var listOfMkabala = ArrayList<MeetingDetails>()
var context: Context? = null
constructor(context: Context, listOfMkabaln: ArrayList<MeetingDetails>) : super() {
this.listOfMkabala = listOfMkabaln
this.context = context
}
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
val mo3d = listOfmo3d[p0]
var inflatormo3d = context!!.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
var myViewmo3d = inflatormo3d.inflate(R.layout.fragment_item, null)
lvMo3d.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, i, l ->
Toast.makeText(context, " TEST STACK ", Toast.LENGTH_LONG).show()
}
myViewmo3d.meeting_name.text = mo3d.name1!!
myViewmo3d.meeting_date.text = mo3d.date.toString()!!
myViewmo3d.attendance_number.text = mo3d.n2.toString()!!
return myViewmo3d
}
override fun getItem(p0: Int): Any {
return listOfmo3d[p0]
}
}
I want listener for each item in my ListView
And when I used this method setOnClickListener in adapter it's not working, where can I use?
Try this in your activity class
lv.setOnItemClickListener { parent, view, position, id ->
Toast.makeText(this, "Position Clicked:"+" "+position,Toast.LENGTH_SHORT).show()
}
Although a little quirky this works fine for me.
latestMessagesAdapter.setOnItemLongClickListener { item, view ->
val row = item as LatestMessageRow
return#setOnItemLongClickListener(true)
}
First of all I would like to tell that it is RecyclerView rather than ListView. You can find plenty information why to do in such. For example you can read it hear :
RecyclerView vs. ListView
Regarding your question how to do it in correct way with RecyclerView.
Insert dependencies with RecyclerView, they are now in support library in Kotlin.
implementation "com.android.support:appcompat-v7:25.4.0"
First change your ListView with RecyclerView in xml layout like this:
<android.support.v7.widget.RecyclerView
android:id="#+id/accountList"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Create Adapter for RecyclerView:
class AccountListAdapter(val accountList: AccountList, val itemListener: (Account) -> Unit) :
RecyclerView.Adapter<AccountListAdapter.ViewHolder>(){
override fun getItemCount(): Int = accountList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) =
holder.bind(accountList[position])
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder{
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_account, parent, false)
return ViewHolder(view, itemListener)
}
class ViewHolder(itemView: View, val itemClick: (Account) -> Unit): RecyclerView.ViewHolder(itemView){
fun bind(account : Account){
with(account){
itemView.accountName.text = title
itemView.setOnClickListener{ itemClick(this)}
}
}
}
}
item_account.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/accountName"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Models (in Kotlin you can put them in one file and name for example AccountModels.kt) :
data class AccountList(val accounts: List<Account>){
val size : Int
get() = accounts.size
operator fun get(position: Int) = accounts[position]
}
data class Account(val id : Long, val title : String, val balance : Int, val defCurrency: Int)
In Fragment/Activity connect your Adapter to RecyclerView:
override fun onStart() {
super.onStart()
setupAdapter()
}
fun setupAdapter(){
Log.d(TAG, "updating ui..")
val account1 = Account(1,"Credit", 1000, 2)
val account2 = Account(2, "Debit", 500, 2)
val account3 = Account(3, "Cash", 7000, 2)
val accounts : List<Account> = listOf(account1, account2, account3)
val adapter = AccountListAdapter(AccountList(accounts)){
val title = it.title
Log.d(TAG, "$title clicked")
}
accountList.layoutManager = LinearLayoutManager(activity)
accountList.adapter = adapter
}
That is all. Everything should work now. Hope it helps.

Categories

Resources