setText() of EditText not working inside onTextChanged method - android

From a newbie in android, I have a custom ListView of food items, where each item has item name, quantity and amount. quantity is Edit text and amount is text view. Initially in amount field i'm displaying price for one quantity of item. when the user enters the quantity (Integer) i'm trying to multiply the quantity with amount and display the total amount in the same text view(i.e textView amount)
So i'm using onTextChanged of TextWatcher .
When the user enters the quantity i'm able to receive it and multiply with original amount to get the total amount but when i'm trying to set it using textviewAmount.setText(total amount) inside onTextChanged method its not working.
While searching for the solution I came across this this .which says
"The EditText appears to have an issue with resetting text in onCreateView"
Below is
the sample code of what i have done
Fragment
public class FoodListFragment extends Fragment {
List<FoodListCell> foodListCells ;
ListView listView ;
HotelApp hotelApp;
FragmentTransaction ft;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
hotelApp = (HotelApp)getActivity().getApplicationContext();
View view = inflater.inflate(R.layout.food_listview,container,false);
Log.d("FoodListActivity" ," onCreate");
foodListCells = new ArrayList<>();
listView = (ListView)view.findViewById(R.id.list_view);
foodListCells.add(new FoodListCell("Diet-Vegetable Soup","75.0"));
foodListCells.add(new FoodListCell("Bean-Bacon ","95.0"));
foodListCells.add(new FoodListCell("Chicken Noodle Soup","75.0"));
FoodListAdopter adapter = new FoodListAdopter(hotelApp, R.layout.foodbox_layout, foodListCells);
listView.setAdapter(adapter);
return view;
}}
Adopter
public class MenuAdopter extends ArrayAdapter<FoodListCell> {
Context context;
int resource;
List<FoodListCell> foodListCells;
HotelApp hotelApp;
EditText quantity ;
TextView foodBoxAmt ;
Double finalAmt = 0.0, amtForOne = 0.0;
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
hotelApp = (HotelApp)this.context;
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.foodbox_layout,null);
TextView foodBoxDesc = (TextView) view.findViewById(R.id.foodBoxDesc);
foodBoxAmt = (TextView) view.findViewById(R.id.foodBoxAmt);
Button button = (Button) view.findViewById(R.id.addToCartButton);
quantity = (EditText) view.findViewById(R.id.qnty);
final FoodListCell foodListCell = foodListCells.get(position);
foodBoxDesc.setText(foodListCell.getDesc());
foodBoxAmt.setText("Rs." +foodListCell.getPrice());
amtForOne = Double.parseDouble(foodListCell.getPrice().toString());
quantity.addTextChangedListener(new EditTextListener(){
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
finalAmt=Double.parseDouble(foodListCell.getPrice().toString())*Double.parseDouble(s.toString());
foodBoxAmt.setText("Rs." +finalAmt.toString());
}}
);
return view;
}}
TextWatcher
public class EditTextListener implements TextWatcher {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}}
Thanks for your help :)

Well, This is not the right way to handle this, Even if you figure out a way to set the text on textview, After you scroll the page the view is getting destroyed and next time when it gets created it uses the default value and not the one you specified!
I suggest two things, First do not use ListView, Instead use RecylerView. RecyclerView is a replacement for ListView since 2 years ago. Second and more importantly whenever your list changes don't update the view, update the model itself, then ask the adapter to recreate the view. It will create the view with updated values. You just have to call notifyDataSetChanged() on the adapter.

Please use String.valueOf(value)
If still value does not set than their is some problem in adapter view .

Related

Update TextView in selected RecyclerView rows

I have a RecyclerView inside a fragment where each line has an adapter which inflates a layout which looks as follows:
I want to access to the value of the EditText (in the following code numberET) of each row and pick the value if EditText is not empty.
How can I cycle on each element of the RecyclerView (I think inside the adapter) to have this behaviour? How can I access the EditText for each element to retrieve the value and use them inside the fragment?
Adapter:
`
public class UserFBEditTextAdapter <T extends UserFBEditTextAdapter.ViewHolder> extends UserFBAdapter<UserFBEditTextAdapter.ViewHolder>{
public UserFBEditTextAdapter(List<UserFB> users,int layoutId, Context context) {
super(users, layoutId, context);
}
#Override
public UserFBEditTextAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new UserFBEditTextAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(UserFBAdapter.ViewHolder holder, int position) {
holder.userFB = users.get(position);
holder.usernameTV.setText(holder.userFB.getName());
}
public class ViewHolder extends UserFBAdapter.ViewHolder {
protected EditText numberET;
public ViewHolder(View itemView) {
super(itemView);
numberET = (EditText) itemView.findViewById(R.id.number_et);
}
}
}`
Fragment:
public class ExpenseCustomFragment extends Fragment {
private OnFragmentInteractionListener mListener;
private UserFBAdapter adapter;
private RecyclerView userCustomList;
public ExpenseCustomFragment() {
// Required empty public constructor
}
public static ExpenseCustomFragment newInstance() {
ExpenseCustomFragment fragment = new ExpenseCustomFragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_expense_custom, container, false);
userCustomList = (RecyclerView) view.findViewById(R.id.amountlist_rv);
userCustomList.setLayoutManager(new LinearLayoutManager(getContext()));
NewExpenseDescriptionActivity activity = (NewExpenseDescriptionActivity) getActivity();
adapter = new UserFBEditTextAdapter(activity.getUsersGroup(), R.layout.listitem_expensecustom, getContext());
userCustomList.setAdapter(adapter);
return view;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
You have to retain that data in some map-based data structure, and then, whenever those values are needed, iterate over that data structure.
You cannot rely on saving that data in a ViewHolder, because ViewHolders are being reused as soon as you perform scrolling. If you currently do not save the data that is filled in EditText, then you'll lose that data if you have many items and perform scrolling (i.e. screen fits 10 items, but your adapter is 20 items, as soon as you scroll to 15th item, the EditText value for the first item will be lost).
private Map<Integer, String> map = new ArrayMap<>(adapterSize);
...
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
String text = map.get(holder.getAdapterPosition());
// maybe we haven't yet saved text for this position
holder.editText.setText(text != null ? text : "");
// updated value in map as soon as the `EditText` in this position changes
holder.editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
map.put(holder.getAdapterPosition(), s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
Now you'll have access to all EditText values in your RecyclerView. The only change that you can consider is updating map after user stops typing. Currently if user types "123456789" the map will be updated 9 times, whereas we need only once. An easy solution to this can be using RxJava's debounce operator combined with RxBinding library. This maybe sounds complicated, but you can see how plain it is in this answer.
This will work. But after you perform scrolling up and forth, soon you'll find out that some mess is going on there. That's because each time onBindViewHolder() gets called a new TextWatcher is being added to the EditText that already has a TextWatcher attached to it. Thus, you also have to take care of removing the TextWatcher after your ViewHolder is being recycled.
But there is no an API to remove all TextWatcher of the EditText. You can use a custom EditText implementation shown in this answer which will clear all TextWatcher attached to this EditText:
#Override
public void onViewRecycled(MyViewHolder holder) {
holder.editText.clearTextChangeListeners();
super.onViewRecycled(holder);
}

Recycler View Adapter with EditText

Ok, my problem is saving inputs of edit text.
I have a recycler view with some edit text inside. I have an adapter and button "add" to add another new edit text. There is a problem because if I write something inside one edit text it doesn't always save when I change focus or I cick on "add" button.
Here is my hosting fragment:
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(view.getContext());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new AddPlayerAdapter(players);
mRecyclerView.setAdapter(mAdapter);
addButton.setOnClickListener {
// overrides
players.add(new Player(""));
mAdapter.notifyDataSetChanged();
}
So now, after click on "add" button new Player class is added to class Players (item players) and adapter is notified, I see on my screen that new item is added (declared in AddPlayerViewHolder). It works fine.
Here are fragments of my adapter class:
public AddPlayerAdapter(Players players) {
this.players = players;
}
#Override
public AddPlayerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.add_player, parent, false);
return new AddPlayerViewHolder(v);
}
#Override
public void onBindViewHolder(final AddPlayerViewHolder holder, final int position) {
holder.name.setText(players.get(position).getName());
holder.name.setHint("Player " + Integer.toString(position+1));
holder.name.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
if (view != null) players.get(position).setName(holder.name.getText().toString());
}
});
}
So each time focus is changed field is updated and it should contain actual data.
But, when I put some data in one edit text, then press "start" button (which open another fragment with "players" data) the focus don't lose and data is not updated. So, I think the idea with OnFocusChangeListener is wrong, but I don't see here anything better.
Could anyone of you make me an example of proper update data inside edit text boxes like here?
I think it is common problem, hope someone will be interested in solution.
You can simply add TextWatcher to save entered player name.
public class EditTextSaverWatcher implements TextWatcher {
private Player player;
public MyTextWatcher(Player player) {
this.player= player;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Another option is to save name here
}
#Override
public void afterTextChanged(Editable s) {
player.setName(s.toString());
}
}
To add the text watcher, you should use
editText.addTextChangedListener(new EditTextSaverWatcher(concretePlayer));

Custom ListView adapter. TextChangedListener calls for wrong EditText

I have the list of travelers with custom adapter what consist two EditText - edtFirstName and edtLastName. I want when user enters text save changes to List, and when next button click send this List to another activity.
My code:
public class TravellersAdapter extends BaseAdapter {
private List<Traveler> itemsList;
private LayoutInflater inflater;
private Activity context;
public TravellersAdapter(Activity context, List<Traveler> itemsList) {
super();
this.itemsList = itemsList;
this.context = context;
inflater = LayoutInflater.from(context);
}
public int getCount() { return itemsList.size(); }
public Object getItem(int i) { return itemsList.get(i); }
public View getView(final int position, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.traveller_item, null);
}
Traveler currentItem = (Traveler) getItem(position);
EditText firstNameView = (EditText) view.findViewById(R.id.edtFirstName);
firstNameView.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable editable) {
currentItem.setFirstName(editable.toString());
}
});
return view;
}
}
For exemple List itemsList consist 5 items. When I edit 2-4 element all ok, but when I edit first or last element edited value assigned to all element in List. In dubugger i saw that method afterTextChanged calls 5 times with different values of position.
How to fix it?
in getView method, the parameter position gives the position of the newly created childView, not the clicked childView's position.
use this to get the correct position:
final int actual_position = myList.getPositionForView((View) v.getParent());
in onClick(View v); of the onClickListener of any View. In you case, you must implement onTextChangedListener for that EditText.
here:
myList is the ListView
v is the View you clicked, in this case the childView of the parent(myList).
The issue happens because views are reusable (that is by design in Android API). So eventually you may assign more than 1 text watcher to the same text view. And all of the assigned watchers are fired when text inside of the text view is changed.
A quick fix (and non-optimal if the list is really long, say, of 1000+ items) would be to have a map of Traweller -> TextWatcher.
Then inside of getView() you can do this (pseudo-code):
check the map if there is a TextWatcher for this Traweller
if map does not have any, then create a new TextWatcher, put in the map and assign to EditText
otherwise detach the TextWatcher from the EditText and remove from the map
create a new TextWatcher, put in the map and assign to EditText
Create one more EditText in the screen that is invisible with name invivisbleEt.
And do the following thing in the addTextChangedListener
firstNameView.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable editable) {
if(!firstNameView.isFocused())
currentItem.setFirstName(editable.toString());
}
});
Also add this code in the onCreate method for ListView object.
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
//public boolean scrolling;
#Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
invivisbleEt.requestFocus();
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});

Android Handling many EditText fields in a ListView

Just a basic question: If I have several dozen EditText fields that are part of a ListAdapter, how can the individual EditText fields know to which row they belong?
Currently I am using TextWatcher to listen for text input. I have tried extending TextWatcher so that I can pass in the position of the EditText to TextWatcher's constructor.
However, when the soft keyboard pops up, the positions that correspond to the various EditText fields shuffle.
How can I track the EditText fields to their proper position?
I am using a GridView to lay things out. The layout of each item is an ImageView with a TextView and EditText field below it.
The text for each EditText is held in a global String array called strings. It is initially empty, and is updated by my TextWatcher class.
public void initList()
{
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.shape, strings)
{
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.shape, null);
}
final String theData = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.shape_edittext);
editText.setText(theData);
editText.addTextChangedListener(
new MyTextWatcher(position, editText)
);
ImageView image = (ImageView) convertView.findViewById(R.id.shape_image);
image.setBackgroundResource(images[position]);
TextView text = (TextView) convertView.findViewById(R.id.shape_text);
if (gameType == SHAPES_ABSTRACT)
text.setText("Seq:");
else
text.setVisibility(View.GONE);
return convertView;
}
#Override
public String getItem(int position) { return strings[position]; }
};
grid.setAdapter(listAdapter);
}
private class MyTextWatcher implements TextWatcher {
private int index;
private EditText edittext;
public MyTextWatcher(int index, EditText edittext) {
this.index = index;
this.edittext = edittext;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) { strings[index] = s.toString(); }
public void setIndex(int newindex) { index = newindex; }
}
When I click into the first EditText (see picture), the EditText shifts to the one under the smiley face.
Not taking into account if this is a good UI design, here's how you'd do it:
public class TestList
{
public void blah()
{
ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
{
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
}
final DataBucket dataBucket = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.theText);
editText.setText(dataBucket.getSomeData());
editText.addTextChangedListener(new TextWatcher()
{
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void afterTextChanged(Editable editable)
{
dataBucket.setSomeData(editable.toString());
}
});
return convertView;
}
};
}
public static class DataBucket
{
private String someData;
public String getSomeData()
{
return someData;
}
public void setSomeData(String someData)
{
this.someData = someData;
}
}
}
'DataBucket' is a placeholder. You need to use whatever class you created to store the data that gets put into and edited in the edit text. The TextWatcher will have a reference to the data object referenced. As you scroll, the edit text boxes should get updated with current data, and text changes should be saved. You may want to track which objects were changed by the user to make data/network updates more efficient.
* Edit *
To use an int position rather than directly referencing the object:
ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
{
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
}
final DataBucket dataBucket = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.theText);
editText.setText(dataBucket.getSomeData());
editText.addTextChangedListener(new TextWatcher()
{
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void afterTextChanged(Editable editable)
{
getItem(position).setSomeData(editable.toString());
}
});
return convertView;
}
};
* Edit Again *
I feel compelled to say for posterity, I wouldn't actually code it this way. I'd guess you want a little more structured data than a String array, and you're maintaining the String array outside, as well as an ArrayAdapter, so its sort of a weird parallel situation. However, this will work fine.
I have my data in a single String array rather than a multi-dimensional array. The reason is because the data model backing the GridView is just a simple list. That may be counterintuitive, but that's the way it is. GridView should do the layout itself, and if left to its own devices, will populate the row with variable numbers of cells, depending on how much data you have and how wide your screen is (AFAIK).
Enough chat. The code:
public class TestList extends Activity
{
private String[] guess;
//Other methods in here, onCreate, etc
//Call me from somewhere else. Probably onCreate.
public void initList()
{
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, /*some resourse id*/, guess)
{
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
}
final String theData = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.theText);
editText.setText(theData);
editText.addTextChangedListener(
new MyTextWatcher(position)
);
return convertView;
}
};
gridView.setAdapter(listAdapter);
}
class MyTextWatcher extends TextWatcher {
private int position;
public MyTextWatcher(int position) {
this.position = position;
}
public void afterTextChanged(Editable s) {
guess[position] = s.toString();
}
// other methods are created, but empty
}
}
To track the row number, each listener in EditText has to keep a reference to an item in a list and use getPosition(item) to get the position in a ListView. My example uses Button but I think that it can be applied to EditText.
class DoubleAdapter extends ArrayAdapter<Double> {
public DoubleAdapter(Context context, List<Double> list) {
super(context, android.R.layout.simple_list_item_1, list);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_row, null);
}
// keep a reference to an item in a list
final Double d = getItem(position);
TextView lblId = (TextView) convertView.findViewById(R.id.lblId);
lblId.setText(d.toString());
Button button1 = (Button) convertView.findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// the button listener has a reference to an item in the list
// so it can know its position in the ListView
int i = getPosition(d);
Toast.makeText(getContext(), "" + i, Toast.LENGTH_LONG).show();
remove(d);
}
});
return convertView;
}
}
It might be worth considering whether you need the edit texts to be stored in the list cells? It seems a little bit unnecessary when the user will only be editing one at a time.
Whilst I do not know how your app is designed I would recommend rethinking your user experience slightly so that when an list item is pressed a single text edit appears for them to edit. That way you can just get the list items reference as you normally would with a list adapter, store it whilst the user is editing and update it when they have finished.
i'm not sure if that's a nice design you have, as the EditText content will have a good chance of having problems (shuffling content, missing text) once your listview is scrolled. consider trying out m6tt's idea.
but if you really want to go your way, can you post some code, specifically of your TextWatcher?
I tried to solve this and as you can see there is a simple method - I am posting the answer here as it might be useful for someone.
Not able to get the position when list view -> edit text has a text watcher.
This is the solution that worked for me :
In get view -
when I add the text watcher listener to edit text, I also added the below line
edittext.setTag(R.id.position<any unique string identitiy>, position)
in your afterTextChanged -
int position = edittext.getTag(R.id.position)
Gives the correct position number and you can do modifications based on the position number.

How to get the Value out of an RecyclerView item

I have a Fragment which carries a Button and a RecyclerView, set up by an RecyclerView Adapter. In the RecyclerView are several Items, one of it is a EditText. Now I want that when the Button is clicked(which is NOT in the RecyclerView object), that I get the values of the EditTexts.
I already tried to get the recyclerView.getItemAtPosition() but there is no function like that, also tried the same for the adapter. So I would need something like
ArrayList s.add(recyclerView.getItemAtPosition(position).getEditText().getText().toString());
This is my Adapter:
public class RVSetAdapter extends RecyclerView.Adapter<RVSetAdapter.ViewHolder> {
private Exercise exercise;
public static class ViewHolder extends RecyclerView.ViewHolder {
public EditText et_weight;
public TextView tv_sets,tv_indication;
public ViewHolder(#NonNull final View itemView) {
super(itemView);
tv_sets = itemView.findViewById(R.id.tv_sets);
tv_indication = itemView.findViewById(R.id.tv_indication);
et_weight = itemView.findViewById(R.id.et_weight);
}
}
public RVSetAdapter(Exercise exercise) {
this.exercise = exercise;
}
#NonNull
#Override
public RVSetAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rv_set,viewGroup,false);
RVSetAdapter.ViewHolder vh_set = new RVSetAdapter.ViewHolder(view);
return vh_set;
}
#Override
public void onBindViewHolder(#NonNull final RVSetAdapter.ViewHolder viewHolder,final int i) {
if(exercise.getKind() == 80) {
viewHolder.tv_sets.setText("");
viewHolder.tv_indication.setText("sec.");
}else if(exercise.getKind() == 90) {
viewHolder.tv_sets.setText("");
viewHolder.tv_indication.setText("min.");
}else {
viewHolder.tv_sets.setText(Integer.toString(i + 1) + ".");
}
viewHolder.et_weight.setText(Integer.toString(exercise.getWeights().get(i)));
}
#Override
public int getItemCount() {
return exercise.getWeights().size();
}
}
this is my Fragment:
final View view = layoutInflater.inflate(R.layout.fragment_exercise, container,false);
ImageView iv_exercise = view.findViewById(R.id.iv_exercise);
ImageView iv_musclekind = view.findViewById(R.id.iv_musclekind);
ImageView iv_save = view.findViewById(R.id.iv_save);
TextView tv_exercisename = view.findViewById(R.id.tv_exercisename);
TextView tv_exercisedescription = view.findViewById(R.id.tv_exercisedescription);
iv_exercise.setImageResource(exercises.get(position).getImage());
iv_musclekind.setImageResource(exercises.get(position).getMusclekindImage());
tv_exercisename.setText(exercises.get(position).getName());
tv_exercisedescription.setText(exercises.get(position).getDescription());
iv_save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//here I want to get the Values of the EditTexts and put them into an Array
}
});
recyclerView = view.findViewById(R.id.rv_sets);
recyclerView.setHasFixedSize(true); //maybe change this
layoutManager = new LinearLayoutManager(view.getContext());
adapter = new RVSetAdapter(exercises.get(position));
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
container.addView(view);
return view;
I don't have any ideas to go on so I would appreciate your help. If there is any uncertainty with my description of the problem please don't hesitate to ask.
Greetings Alexander
With RecyclerView, you have to understand that your EditTexts will be recycled. For example, if you have a list of 200 items, and it shows 2 items at one time, you will only ever have 2 EditText. They will reuse the higher EditText for the lower elements.
For example, here is a list that contains EditText showing only 2 at a time, and as the user scrolls, it will recycle and reuse them.
EditText A
Edittext B
EditText A (recycled)
EditText B (recycled)
....
This means you cannot just loop over all the elements later and get the values, as they don't store their values.
So, what you want to do, is when the user modifies an EditText, you want to store that value right away. You can do this by adding a TextWatcher to your EditText.
Note - I did assume you store your weights as String values, so I just took the value from the EditText and stored it into your Exercise Object. You may want to convert it before that.
public class RVSetAdapter extends RecyclerView.Adapter<RVSetAdapter.ViewHolder> {
private Exercise exercise;
// ...
#Override
public void onBindViewHolder(#NonNull final RVSetAdapter.ViewHolder viewHolder,final int i) {
// ...
viewHolder.et_weight.setText(Integer.toString(exercise.getWeights().get(i)));
viewHolder.et_weight..addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
// This will be the text from the EditText
String text = s.toString();
// Store the value back into your exercise Object.
exercise.getWeights().get(i).setWeight(text);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
});
}
// ...
// Add a method for easy access to your weights.
public ArrayList<String> getWeights() {
return exercise.getWeights();
}
}
And now, within your Fragment, you can easily get the values out of your RVSetAdapter.
public View onCreateView() {
final View view = layoutInflater.inflate(R.layout.fragment_exercise, container,false);
// ...
iv_save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Use the method we added to your adapter to return the weights.
ArrayList<String> weights = adapter.getWeights();
}
});
// ...
return view;
}
I think you should use ArrayList in Adapter class to keep your items (or just Strings of EditText components). Add String to ArrayList in your onBindViewHolder() after you set text for editext. Then make a function which will get item from your ArrayList like:
public String getItem(int position){
arrayList.get(position);
}
and call it from your onClick() function in Fragment.
I think you can create static button and you can then access that button in your adapter then implement the functionality on the onclick of your button.
static Button btn;
Then implement like this in your adapter...
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
for(int i=0;i<arraylist.size();i++)
{
arr[i]= holder.edit_Text.getText().toString();
}
}
});
and put this onclick in your onbindviewholder method.

Categories

Resources