How to Get the Text from Edittext of a Recyclerview Item When User Clicks on a Button of the Same Item

How can I get the text from EditText of a recyclerview item when user clicks on a button of the same item?

First of, you need two references: one to your EditText and one to your Button. You can get those in your ViewHolder. Next, you need an OnClickListener. The ViewHolder can conveniently also implement one but you could also use onBindViewHolder() for that.

Inside that OnClickListener you can filter out your id with a switch statement if you want to and then get the content of the EditText like this:

switch(viewId) {
case R.id.buttonId:
String text = editText.getText().toString();
// do something with that text
return true;
}

In case you implemented an OnClickListener in your ViewHolder you can then do this button.setOnClickListener(this); inside your ViewHolder to make sure onClick() is actually called when you click the button.

EDIT:
Here's some sample code that should work for your case. I'm implementing View.OnClickListener here as mentioned above.

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

EditText editText;
Button button;

public ViewHolder(View itemView) {
super(itemView);

editText = itemView.findViewById(R.id.editText);
button = itemView.findViewById(R.id.button);
button.setOnClickListener(this);
}

@Override
public void onClick(View view) {
switch(view.getId()) {
case R.id.button:
String text = editText.getText().toString();
break;
}
}
}

This is what it would look like if you were to do it in your onBindViewHolder() (in this case you would NOT implement the OnClickListener in your ViewHolder obviously):

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String text = holder.editText.getText().toString();
}
});
}

I get null reference of EditText of a recyclerview item when user clicks on a button of the same item

I think there's an id mismatch, you are searching for an id but on XML there's a different id

email =  itemView.findViewById(R.id.emailBox);

android:id="@+id/emailbox"

How to get values from editText and other fields from recyclerview adapter for a submit

solved by following this tutorial

https://demonuts.com/android-recyclerview-with-edittext/

and when modified for my code, I get the values by doing this and accesing at the push of a button:

public void getEditValue(){

for(int i=0;i<saleDetailList.size();i++)
{
View view=rcvMoneyDevolution.getChildAt(i); // This will give you entire row(child) from RecyclerView
if(view!=null)
{
TextView textView= view.findViewById(R.id.txtSVSaleDetailsAdapter);
Log.e("Tag",textView.getText().toString());
Spinner mySpinner = view.findViewById(R.id.spnQuantityProducttoDevolution);
String text = mySpinner.getSelectedItem().toString();
Log.e("Tag",text);
String moneyDevolution = MoneyDevolutionAdapter.editModelArrayList.get(i).getEditTextValue();
Log.e("Tag",moneyDevolution);

}
}

}

Saving EditText content in RecyclerView

The major problem with your solution is allocating and assigning TextWatcher in onBindViewHolder which is an expensive operation that will introduce lags during fast scrolls and it also seems to interfere with determining what position to update in mAdapter.

Making all operations in onCreateViewHolder is a more preferable option. Here is the complete tested working solution:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

private String[] mDataset;

public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}

@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_edittext, parent, false);
// pass MyCustomEditTextListener to viewholder in onCreateViewHolder
// so that we don't have to do this expensive allocation in onBindViewHolder
ViewHolder vh = new ViewHolder(v, new MyCustomEditTextListener());

return vh;
}

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
// update MyCustomEditTextListener every time we bind a new item
// so that it knows what item in mDataset to update
holder.myCustomEditTextListener.updatePosition(holder.getAdapterPosition());
holder.mEditText.setText(mDataset[holder.getAdapterPosition()]);
}

@Override
public int getItemCount() {
return mDataset.length;
}


public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public EditText mEditText;
public MyCustomEditTextListener myCustomEditTextListener;

public ViewHolder(View v, MyCustomEditTextListener myCustomEditTextListener) {
super(v);

this.mEditText = (EditText) v.findViewById(R.id.editText);
this.myCustomEditTextListener = myCustomEditTextListener;
this.mEditText.addTextChangedListener(myCustomEditTextListener);
}
}

// we make TextWatcher to be aware of the position it currently works with
// this way, once a new item is attached in onBindViewHolder, it will
// update current position MyCustomEditTextListener, reference to which is kept by ViewHolder
private class MyCustomEditTextListener implements TextWatcher {
private int position;

public void updatePosition(int position) {
this.position = position;
}

@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
// no op
}

@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
mDataset[position] = charSequence.toString();
}

@Override
public void afterTextChanged(Editable editable) {
// no op
}
}
}

How to detect when user's done entering the value to EditText in RecyclerView?

Idea

Best way is to add two communications (via interfaces):

  • FIRST between Activity and Adapter

  • SECOND between Adapter and single ViewHolder

Affter adding such type of communication your can calculate sum "live".

Solution

Step #1

Create FIRST interface, for example:

interface AdapterContentChanged {
fun valuesChanged()
}

and implement it in your Activity or create new variable (as anonymous class).

Step #2

Pass your activity (or instance of above interface) when you are creating adapter, for example:

private val ownAdapter = OwnAdapter(
items, // elements inside list
this // interface implementation
)

Step 3

Create SECOND interface, for example:

interface OwnViewHolderTextChanged {
fun onTextChanged(position: Int, newValue: Int)
}

and implement it in your adapter or create new variable (anonymous class) - same like in step #1.

Step 4

Pass your adapter (or variable) and position (of the item) when you are binding viewHolder, for example:

override fun onBindViewHolder(holder: OwnViewHolder, position: Int) {
val number = list[position]
holder.bind(number, position, this)
}

Step 5

In bind() method (from above example), add new TextWatcher to your EditText.

In afterTextChanged() method (from TextWatcher) call method from interface and pass new value. For example:

fun bind(
// TODO - add here more information which you need,
position: Int,
listener: OwnViewHolderTextChanged
) {
itemView.edit_text.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
// Get EditText content
val newValue = getNumber()

// Call method from interface
listener.onTextChanged(position = position, newValue = newValue)
}

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
// Not used
}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
// Not used
}

})
}

To calculate value from EditText you can use something like this:

private fun getNumber(): Int =
try {
itemView.edit_text.text.toString().toInt()
} catch (e: Exception) {
0
}

Step 6

When text was changed inside method you have to:

  • update content of the list

  • notify adapter that "something was changed"

For example:

override fun onTextChanged(position: Int, newValue: Int) {
list[position] = newValue
listener.valuesChanged()
}

Step 7

When something changed (and Activty will know about that), you can calculate new sum:

override fun valuesChanged() {
val sum: Int = ownAdapter.getCurrentSum()
text_view.text = "Sum: $sum"
}

Demo

demo



Related Topics



Leave a reply



Submit