EditText getting defocused on refresing recyclerview - android

EditText in recyclerview
I am using a Recyclerview to show a list of EditText.
My requirement is whenever I click on EditText it should open a numeric keypad and the item should get highlighted as it is getting selected.
My Code does the following:
My fragment is the listener of the item clicked.
Whenever item gets clicked it calls the listener method in the fragment, that methods updates the selected item and it refreshes the adapter so that the selected item gets highlighted.
Listener method in fragment:
#Override
public void itemClicked(int position) {
for (MyClass myObject : myObjectList) {
myObject.isSelected = false;
}
myObjectList[position].isSelected = true;
myRecyclerViewAdapter.notifyDataSetChanged();
}
In my adapter:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if(myObjectList[position].isSelected){
// highlight this item
}else{
// do not highlight this item
}
}
This works totally fine. But I want to do same whenever EditText in the item of recyclerview gets clicked.
The problem is:
first of all what kind of listener should I use for EditText click and why?
I used OnFocusChangedListener, There I called my listener method in fragment which selects proper position, but when it refreshes the adapter it defocuses my clicked EditText(defocuses means it removes cursor from clicked edittext) and one more thing it changes the numeric keypad into normal keypad.
myEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (clickListener != null) {
clickListener.itemClicked(getLayoutPosition());
}
}
}
});
The problem is obvious according to my code but I am not getting the trick to solve it.
Any help would be greatly appreciated.

Related

How to update the view of a particular position of a recycler view which is not currently in focus on the screen?

I am actually making some visibility changes to items that are clicked of the recycler view. But when the user clicks on one object and then clicks on the other object then the previous object should come to its initial state.
The manager.findViewByPosition(position) is working fine if the view is in focus of the screen but I am not able to get the view if the element is not in current focus.
For example:- the user clicks on 1st(position) item then clicks on the last position then the findViewByPosition returns a null.
Please help and let me know if there is some other way of doing it.
The expected result should be the view of the last item to be refreshed but it's not happening for the views that are not in the current focus of the screen.
Below is my code snippet. Updated with what you suggested.
public class BodyPartWithMmtRecyclerView extends
RecyclerView.Adapter<BodyPartWithMmtRecyclerView.ViewHolder>
{
//variables defined.
int selectedPosition = -1;
static class ViewHolder extends RecyclerView.ViewHolder {
//All the view items declared here.
ViewHolder(View view) {
super(view);
//All the views are defined here.
}
}
public BodyPartWithMmtRecyclerView(List<BodyPartWithMmtSelectionModel> bodyPartsList, Context context){
//array list initialization and shared preference variables initialization
}
public BodyPartWithMmtRecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//Creating a new view.
}
public void onBindViewHolder(#NonNull final BodyPartWithMmtRecyclerView.ViewHolder holder, #SuppressLint("RecyclerView") final int position) {
BodyPartWithMmtSelectionModel bodyPartWithMmtSelectionModel = bodyPartsList.get(position);
holder.iv_bodypart.setImageResource(bodyPartWithMmtSelectionModel.getIv_body_part());
holder.tv_body_part_name.setText(bodyPartWithMmtSelectionModel.getExercise_name());
if(selectedPosition!=position && selectedPosition!=-1){
//updated the elements view to default view. Like made the visibility and other changes here.
}
//some click listeners on the sub-elements of the items. Like textviews, spinner, etc
holder.iv_bodypart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((BodyPartSelection)context).setFabVisible();
if(selectedPosition!=-1){
((BodyPartSelection)context).visibilityChanged(selectedPosition,position);
/*here what I was doing is whenever the user clicks on an item I check weather a previous item is clicked or not then if yes then I send the position to a function that makes it to default but the issue was that if the item is not in the focus of the screen the findViewByPosition returns null.*/
}
selectedPosition = position;
bodypartSelected = holder.tv_body_part_name.getText().toString();
holder.iv_bodypart.setVisibility(View.INVISIBLE);
holder.rl_left_right.setVisibility(View.VISIBLE);
}
});
//and other listeners below
}
#Override
public int getItemCount() {
return bodyPartsList==null?0:bodyPartsList.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
}
VisibilityChanged function
public void visibilityChanged(int position, int clicked){
View view = manager.findViewByPosition(position);
if(view!=null) {
Log.i("inside","visibility change");
ImageView imageView = view.findViewById(R.id.bodypartImage);
//other elements and changing the visibility of elemets to default.
}
}
I have updated my code based on the snippet you updated. Please don't change the visibility condition if-else I have added with any different logic which I saw in your code snippet. As you did, it will not update both selected and default view as RecyclerView reuse the view layout. So if the condition is not proper, you may see multiple items as selected or some other types of unwated behaviour.
public void onBindViewHolder(#NonNull final BodyPartWithMmtRecyclerView.ViewHolder holder, #SuppressLint("RecyclerView") final int position) {
BodyPartWithMmtSelectionModel bodyPartWithMmtSelectionModel = bodyPartsList.get(position);
holder.iv_bodypart.setImageResource(bodyPartWithMmtSelectionModel.getIv_body_part());
holder.tv_body_part_name.setText(bodyPartWithMmtSelectionModel.getExercise_name());
if(selectedPosition == position){
//updated the elements view to SELECTED VIEW. Like made the visibility and other changes here.
} else {
//updated the elements view to default view. Like made the visibility and other changes here.
}
//some click listeners on the sub-elements of the items. Like textviews, spinner, etc
holder.iv_bodypart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((BodyPartSelection)context).setFabVisible();
/Comment by Hari: Don't try to change the visibility of default as it will be done automatically after calling notifyDataSetChanged(). */
if(selectedPosition!=-1){
((BodyPartSelection)context).visibilityChanged(selectedPosition,position);
/*here what I was doing is whenever the user clicks on an item I check weather a previous item is clicked or not then if yes then I send the position to a function that makes it to default but the issue was that if the item is not in the focus of the screen the findViewByPosition returns null.*/
/*Comment by Hari: This snippet is valuable which is missing as you are getting null issue here.
However Don't try to change the visibility of default as it will be done automatically after calling notifyDataSetChanged(). */
}
selectedPosition = position;
bodypartSelected = holder.tv_body_part_name.getText().toString();
holder.iv_bodypart.setVisibility(View.INVISIBLE);
holder.rl_left_right.setVisibility(View.VISIBLE);
//Keep this as last statement in onClick
notifyDataSetChanged();
}
});
//and other listeners below
}
Let me know your further response.
Based on #Hari N Jha's Answer.
Call notifyDataSetChanged() when you update anything. E.g
int selectedPosition = -1;
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//....
if(position == selectedPosition) {
//Add background color change of your layout or as you want for selected item.
} else {
//Add background color change of your layout or as you want for default item.
}
notifyDataSetChanged(); //Call notifyDataSetChanged() here after done all the stufs
//...
}

Delete edittext value in the recyclerview

Currently: i have a recycler view where it has delete button and an edit text for each item.
Each item in the recycler view contains edit text that the user can input.
The scenario is i have 4 item in the list resulting 4 edit text.
When i try to fill up edit Text in the item(n) and tried to delete
the item(n) and add again. The edit Text value in the edit text remains.
How can i clear the value of the edit text?
Here is my current code when i try to delete a specific item in the list:
mHeaderText.remove(pos);
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int i = 1 ; mHeaderText.size() >= i ; i++) {
temp.add(i);
Log.d("ADDDING","ADDDING"+i);
}
mHeaderText.clear();
mHeaderText.addAll(temp);
notifyDataSetChanged();
Try this code ..
In adapter class in onBindView method when you perform click event then set edittext value as null.
edittext.setText("");
and if your edittext box in activity layout then make interface into adapter class and handling click event like this way...
OnItemClick onItemClick;
public void setOnItemClick(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public interface OnItemClick {
void getPosition(String data); //pass any data to shared it.
}
after that..
#Override
public void onBindViewHolder(ItemViewHolder holder, final int position) {
// below code handle click event on recycler view item.
final String data = mStringList.get(position);
holder.textView.setText(data);
holder.firstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.getPosition(data); // shared data.
}
});
}
after that in activity adapter bind into recycler view it means adapter not null then called below line..
adpater.setOnItemClick(new RecyclerViewAdpater.OnItemClick() {
#Override
public void getPosition(String data) {
// hear perform any operation.
editTextbox.setText("");
adpater.notifyDataSetChanged();
}
});
Use
edittext.setText("");
to clear text where edittext is reference to EditText. Since you haven;t posted complete code so i can guide to this only. If you provide more code, then I can help you more.
One thing is sure. You will need to use
edittext.setText("") to clear the value.
But you need to be careful. You need to keep this as the first line in your delete row function, i.e. before you are removing that edittext item from your list.
Here is my code: I have placed the "remove row" function inside onBindViewHolder() method of Recyclerview Adapter.
holder.delImgView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// You need to place it in the start
holder.editText.setText("");
// Remove the item on remove/button click
myArrayList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, myArrayList.size());
Toast.makeText(context, "Removed : " + position +" item", Toast.LENGTH_SHORT).show();
}
});

RecyclerView changes multiple rows although only one row was targeted

I got a RecyclerView and want to change the appearance of any clicked row. For that I have a callbackFunction in my Activity which I pass to the Adapter, which then is called inside the Adapter, as soon as I click on any row in the RecyclerView.
The clicked row is then changed, but it happens, that not only the clicked rows are changed but also other rows, that weren't clicked and were never clicked before. I checked the ArrayList that contains the data, but everything is fine there. Only the clicked elements contain the trigger to change the appearance of the row.
What is causing the other rows to change, although they have not been clicked?
Interface inside activity for callback
public interface onHeaderClickListener{
void onHeaderClicked(int index);
}
Inside RecyclerView Adapter
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ViewHolderHeader){
((ViewHolderHeader)holder).dateHeaderTextView.setText( Integer.toString(((objClass_offerDateHeader) arrayList.get(position)).getDate()));
if(((objClass_offerDateHeader) arrayList.get(position)).isSelected()){
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#b642f4"));
}
((ViewHolderHeader)holder).dateHeaderTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onHeaderClickListener.onHeaderClicked(position);
}
});
}
}
Adapter initialisation inside activity
customAdapterRecyclerViewAddOffersTo = new customAdapterRecyclerViewAddOffers(offerArrayList,"dragTo", new onHeaderClickListener() {
#Override
public void onHeaderClicked(int index) {
if (offerArrayList.get(index) instanceof objClass_offerDateHeader){
if(((objClass_offerDateHeader) offerArrayList.get(index)).isSelected()){
((objClass_offerDateHeader) offerArrayList.get(index)).setSelected(false);
}
else {
((objClass_offerDateHeader) offerArrayList.get(index)).setSelected(true);
}
customAdapterRecyclerViewAddOffersTo.notifyDataSetChanged();
}
}
});
In your onBindViewHolder method you have to set the background of the unselected cell, keep in mind the the cells are reused and you only set the background of selected cells so when it is reused the background is not returned to the normal color
So in code you will have to add an else condition
if(((objClass_offerDateHeader) arrayList.get(position)).isSelected()){
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#b642f4"));
} else {
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#FFFFFF")); // I assume you need it to be white you can change it to any other color
}
You need to add an else condition here:
if(((objClass_offerDateHeader) arrayList.get(position)).isSelected()){
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#b642f4"));
}
Viewholders get recycled, so you cannot be sure of the current state when onBindViewHolder is called.

Item is not getting selected on spinner when used in recyclerview

I have a weird problem when using spinner widget inside a recyclerview. So the story is like this I have a recyclerview which has the spinner and I am passing list which needs to be inflated from fragment to the recyclereview where I am creating adapter if the data is not null and setting it into the spinner, but it works sometimes and most of the times not. It also works when getting focus or typing in edit text below it.
Note: I have already checked the other questions related this and yes I am using a white background with black text color layout which is basically a custom layout for the spinner. I am having a hard time figuring out what is going on.
This is my code for setting spinner in onBindViewHolder()
#Override
public void onBindViewHolder(FamilyMemberAdapter.ViewHolder holder, int position) {
FamilyMemberRecyclerViewModel familyMemberModel = familyMemberRecyclerViewModelList.get(holder.getAdapterPosition());
if (familyMemberModel.getRelationTypeModelList()!=null){
relationTypeModelArrayAdapter = new ArrayAdapter<RelationTypeModel>(context,R.layout.item_spinner,familyMemberModel.getRelationTypeModelList());
holder.spnRelationType.setAdapter(relationTypeModelArrayAdapter);
if (familyMemberModel.getRelationTypeAdapterModel()!=null){
int positionRelation = relationTypeModelArrayAdapter.getPosition(familyMemberModel.getRelationTypeAdapterModel());
holder.spnRelationType.setSelection(positionRelation);
}
}
}
spinner onItemSelectedListener()
spnRelationType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
//here differentiate between different doc and relation
uploadDocumentItemsClickListener.onSpinnerChangeListener(spnRelationType,getAdapterPosition(),adapterView.getSelectedItemPosition());
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
Here is snapshot of what is going on.
This is I am selecting item from the spinner
This is after selecting an item from the spinner.
Please let me know if more code needed.
I believe this is because the edit text still has the focus and not on the spinner. Try something like this.
spinner.setFocusableInTouchMode(true);
spinner.setOnFocusChangeListener((v, hasFocus) -> {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (spinner.getWindowToken() != null) {
spinner.performClick();
}
}
}
});

Add selected position in RecyclerView to a set and highlight those position

I have a recyclerView and have implemented onLongClick listener on the items. The Adapter is in the same class as the Activity.
I created a set: public Set<Integer> multiplePositions as instance variable of the Activity class and am initialising it in onCreate() method as multiplePositions = new TreeSet<>().Coming to my Adapter class in the onBindViewHolder method I created a click listener as follows:
holder.textCardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Adapter.this.onLongClick(holder, position);
return true;
}
});
holder.textCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
As you can see I am calling the method onLongClick. My onLongClick method looks like this:
public void onLongClick(ViewHolder holder, int position) {
multiplePositions.add(position);
for(Integer i : multiplePositions) {
Log.e("set", ""+i);
}
holder.textCardView.setBackgroundResource(R.color.long_press);
}
Here, whenever an item clicked I am adding the position in the Set but I don't know how do I iterate through this set and set the background color of all the item at the positions in the set.
I am aware that this can be achieved by creating a boolean variable isSelected in the model class but if I go with this method then other functionalities of my code won't work.
My main concern is if I scroll the recyclerView up or down then color of the selected positions should not disappear. The unselection part will be done in setOnClickListener().
Use SparseBoolean array to store the positions of the items clicked in the reyclerview.Check the answer in this link
https://stackoverflow.com/questions/46336645/hilighted-selected-items-colour-changes-when-not-in-view-in-recyclerview/46336844#46336844
Check here the purpose of using SparseBoolean array
https://stackoverflow.com/questions/18822708/what-is-the-clear-purpose-of-sparsebooleanarray-i-referred-official-android
EDIT:
Use SparseBooleanArray to keep track of selected items in recycler view adapter
Initialize the SparseBooleanArray as private memeber variable
private SparseBooleanArray mClickedItems=new SparseBooleanArray();
Inside your click function while clicking textCardView make the item position as true.
holder.textCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mClickedItems.put(position,true);
notifyDataSetChanged();
}
});
Then in the onBindViewHolder check if the position is already selected or not like this
if(mClickedItems.get(position)==true){
//Show selected color
holder.textCardView.setBackgroundResource(ContextCompat.getColor(holder.textCardView.getContext(),R.drawable.selected));
}else {
//show unselected color
holder.textCardView.setBackgroundResource(ContextCompat.getColor(holder.textCardView.getContext(),R.drawable.unselected));
}

Categories

Resources