I have created a simple RecycleView component. Then create a new activity for that component. In one row I have a TextView and Button. What I want to do is to change something in object which was put into the excatly one row.
First I initialized the Button:
public class RecycleViewAllWashesActivity extends Activity {
private Button isFavorite;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.row_recycleview);
isFavorite = (Button) findViewById(R.id.addToFav);
isFavorite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.w("myApp", String.valueOf(v.getId()));
int id = v.getId();
}
});
}
}
The adapter of RecycleView looks like:
#Override
public MyAdapter.WashLocationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View view = inflater.inflate(R.layout.row_recycleview, parent, false);
// Return a new holder instance
WashLocationViewHolder viewHolder = new WashLocationViewHolder(view);
return viewHolder;
}
// Involves populating data into the item through holder
#Override
public void onBindViewHolder(MyAdapter.WashLocationViewHolder viewHolder, int position) {
// Get the data model based on position
WashLocation w = washLocations.get(position);
String info = w.getWashName();
// Set item views based on your views and data model
TextView textView = viewHolder.info;
textView.setText(info);
Integer fav = w.getFav();
Boolean favorite = fav == 1 ? true : false;
Button addToFav = viewHolder.favorite;
addToFav.setText(favorite == true ? "Usuń z ulubionych" : "Dodaj do ulubionych");
}
Questions:
How to get the object which was put into one row?
When I clicked the Button (code above) it doesn't react, even breakpoint which was set there doesn't react? -> the thing in console which I see while clicking the button is:
04-17 13:11:00.137 7671-7671/com.example.micha.locationtest D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
==============================
Update:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ItemHolder> {
private List<WashLocation> washLocations;
private OnItemClickListener onItemClickListener;
private LayoutInflater layoutInflater;
public MyAdapter(List<WashLocation> washLocations, Context context) {
layoutInflater = LayoutInflater.from(context);
this.washLocations = washLocations;
}
#Override
public MyAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = layoutInflater.inflate(R.layout.row_recycleview, parent, false);
return new ItemHolder(itemView, this);
}
#Override
public void onBindViewHolder(MyAdapter.ItemHolder holder, int position) {
// Get the data model based on position
WashLocation w = washLocations.get(position);
String info = w.getWashName();
// Set item views based on your views and data model
TextView textView = holder.info;
textView.setText(info);
Integer fav = w.getFav();
Boolean favorite = fav == 1 ? true : false;
Button addToFav = holder.favorite;
addToFav.setText(favorite == true ? "Usuń z ulubionych" : "Dodaj do ulubionych");
}
#Override
public int getItemCount() {
return washLocations.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
onItemClickListener = listener;
}
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public interface OnItemClickListener {
public void onItemClick(ItemHolder item, int position);
}
/* public void add(int location, String iName){
itemsName.add(location, iName);
notifyItemInserted(location);
}
public void remove(int location){
if(location >= itemsName.size())
return;
itemsName.remove(location);
notifyItemRemoved(location);
}*/
public static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private MyAdapter parent;
TextView textItemName;
public TextView info;
public Button favorite;
public ItemHolder(View itemView, MyAdapter parent) {
super(itemView);
itemView.setOnClickListener(this);
this.parent = parent;
info = (TextView) itemView.findViewById(R.id.textView);
favorite = (Button) itemView.findViewById(R.id.addToFav);
}
public void setItemName(CharSequence name) {
textItemName.setText(name);
}
public CharSequence getItemName() {
return textItemName.getText();
}
#Override
public void onClick(View v) {
final OnItemClickListener listener = parent.getOnItemClickListener();
if (listener != null) {
listener.onItemClick(this, getPosition());
}
}
}
}
The activity class:
final DataBaseHelper dataBaseHelper = new DataBaseHelper(getApplicationContext());
washLocations = dataBaseHelper.getWashLocation();
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mAdapter = new MyAdapter(washLocations, this);
mAdapter.setOnItemClickListener(this);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
#Override
public void onItemClick(MyAdapter.ItemHolder item, int position) {
Log.d("myApp", "fdsgfds");
}
In Recycle review you must set an onClickListener for the views explicitly.
It does not have any default methods to handle click events like the listview.
You need to set an Onclick listener for your button in your WashLocationViewHolder
You will receive a click event there. From the view holder, you can send the event back to your fragment or activity using an interface.
if you need further help regarding this, mention it in the comments. I will provide you some samples.
How to get the object which was put into one row?
To do this you can set the object as a Tag using the setTag(Object) method in the layout or the button for which you will be providing a click listener. Then you can get the object using the getTag() method from the view.
Hope this helps.
Related
I have a recycler view, which consists of list. The items in the list have their own details like this (each item will have image, id, name, description), and the items are shuffeled, not in order.
Example : recyclerview item position = 0, list item id= 7.
recyclerview item position = 1, list item id= 5.
recyclerview item position = 2, list item id= 12.
So i need to get the list item id on recycler on click. If i click on recyclerview position = 0, If i have to get the item id as 7. So that i can work on that furthur based on that id.
My example code is
recommendedrecyclerView=(RecyclerView)view.findViewById(R.id.recommended_recycler_view);
recommendedrecyclerView.setNestedScrollingEnabled(false);
recommendedrecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),OrientationHelper.VERTICAL,true));
recommendedrecyclerView.setItemAnimator(new DefaultItemAnimator());
I am getting data from server and setting it to adapter
setrecommendedAppsContent(response.body().getData());
public void setrecommendedAppsContent(List<FeaturedAppsData> data){
if (data!=null&&data.size()>0) {
recommendedAdapter = new RecommendedAdapter(mCurrentContext, data);
recommendedrecyclerView.setAdapter(recommendedAdapter);
recommendedAdapter.setClickListener(this);
}
}
This is my adapter class
public class RecommendedAdapter extends RecyclerView.Adapter<RecommendedAdapter.ItemViewHolder> {
private LayoutInflater inflater = null;
private Context context;
private List<FeaturedAppsData> itemsData;
private ClickListener clicklistener = null;
public TextView recommendedAppTitle,recommendedAppCategory,recommendedAppDescription;
public ImageView recommendedAppIcon;
Button recommendedBtn;
String appId;
public void setClickListener(ClickListener clickListener) {
this.clicklistener = clickListener;
}
public RecommendedAdapter(Context context, List<FeaturedAppsData> itemsData) {
this.context = context;
this.itemsData = itemsData;
}
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
holder.recommendedAppTitle.setText(itemsData.get(position).getName());
holder.recommendedAppCategory.setText(itemsData.get(position).getApp_description());
holder.recommendedAppDescription.setText(itemsData.get(position).getOffer_description());
holder.recommendedAppBtn.setText(itemsData.get(position).getButton_text());
String imageUrl = String.valueOf(itemsData.get(position).getImage().getUrl());
Glide.with(context).load(ApiConstant.ApiBaseUrl + imageUrl).into(recommendedAppIcon);
appId=itemsData.get(position).getId();
}
#Override
public int getItemCount() {
int size = 0;
if (itemsData != null && itemsData.size() > 0) {
size = itemsData.size();
}
return size;
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView recommendedAppTitle,recommendedAppCategory,recommendedAppDescription,offerDescription,offerDetailDescription,rewardDetail;
public ImageView recommendedAppIcon;
public Button recommendedAppBtn;
public ArrayList<FeaturedAppsData> dataItems;
private Context context;
public ItemViewHolder(Context context, View itemView, int viewType) {
super(itemView);
this.context = context;
itemView.setOnClickListener(this);
recommendedAppTitle = (TextView) itemView.findViewById(R.id.recommended_app_title);
recommendedAppCategory = (TextView) itemView.findViewById(R.id.recommended_app_category);
recommendedAppDescription = (TextView) itemView.findViewById(R.id.recommended_app_description);
recommendedAppIcon = (ImageView) itemView.findViewById(R.id.recommended_app_icon);
recommendedAppBtn=(Button)itemView.findViewById(R.id.recommended_app_card_btn);
}
#Override
public void onClick(View v) {
if (clicklistener != null) {
clicklistener.itemClicked(v, getAdapterPosition());
}
}
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
inflater = LayoutInflater.from(context);
view = inflater.inflate(R.layout.recommended_item_layout, parent, false);
recommendedAppIcon=(ImageView)view.findViewById(R.id.recommended_app_icon);
return new ItemViewHolder(context, view, viewType);
}
}
I am not sure of the Onclick method. So please suggest me as required along with Onclick event.
The setOnClickListener inside the ViewHolder is a good way.
Considering your current solution, the easiest way is to change the ClickListener interface, put the data inside the Holder during onBindViewHolder and then pass it to the listener during onClick. Like this:
Change the view holder fields to:
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView recommendedAppTitle,recommendedAppCategory,recommendedAppDescription,offerDescription,offerDetailDescription,rewardDetail;
public ImageView recommendedAppIcon;
public Button recommendedAppBtn;
public FeaturedAppsData data; // <<< ADD THIS
// remove that u don't need public ArrayList<FeaturedAppsData> dataItems;
// remove that u don't need private Context context;
... the rest of your holder
then inside onBindViewHolder
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
holder.data = itemsData.get(position);
... the rest on bind
then inside onClick, inside the holder:
#Override
public void onClick(View v) {
if (clicklistener != null) {
clicklistener.itemClicked(v, data.getId());
}
}
I have a recyclerView and its items contain a button. And I wanna get the recyclerview item position when I click on the button. Here is the problem, when the button clicked the button clicked event is triggered but the recyclerview item under neath is not, the clicked event can not go through the button on the top to recyclerview item.
How can I get this click-through event or how can I bind them together? Please someone tell me if know the answer.
update:
I could not find any similar post online. usually recyclerview contains button is register to different OnclickedListener. In my case, they need to handle the same listener, particularly the recyclerview handle it. But the button just block the clicked event of recyclerview. here is the viewholder code:
`public class GridViewAdapter extends RecyclerView.Adapter {
private final LinkedList<Device> mValues;
private final OnListFragmentInteractionListener mListener;
private OnLongClickListener mOnLongClickListener = null;
public GridViewAdapter(LinkedList<Device> items, OnListFragmentInteractionListener listener) {
mValues = items;
mListener = listener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.device, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
// holder.mIconView.setImageResource(R.drawable.ic_switch);
holder.mNameView.setText(holder.mItem.device_name());
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (null != mListener) {
mListener.onDeviceClicked(holder.mItem);
}
}
});
}
public void deleteByDeviceCode(int deviceCode) {
for(int i=0;i<mValues.size();i++) {
if (mValues.get(i).device_code() == deviceCode) {
mValues.remove(i);
}
}
}
public void deleteByPosition(int pos) {
mValues.remove(pos);
}
public int getDeviceCodeByPosition(int pos) {
return mValues.get(pos).device_code();
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final Button mButton;
public final TextView mNameView;
public Device mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mButton = (Button) view.findViewById(R.id.dev_button);
mNameView = (TextView) view.findViewById(R.id.dev_lable);
}
#Override
public String toString() {
return super.toString() + " '" + mNameView.getText() + "'";
}
}
}`
When creating view holders, try passing them index of element represented by them, or even reference to whole element. Now, when you've receiving click event in view holder, with event itself you should pass the (index of) element that is represented by that holder/row.
I have created an Adapter and ViewHolder for the recyclerView. I bind the imageButton of the itemView inside the Viewholder. And have set an onClickListener inside the onBindViewHolder.
Everything works as expected but the issue is now when i scroll down the list the selected state of the imageButton changes for the selected item and some of the items on the bottom of the list already appear
selected.
Here is the some code
public class ListViewHolder extends RecyclerView.ViewHolder {
TextView textViewUserName;
ImageButton imageButtonCheckMark;
public ListViewHolder(View itemView) {
super(itemView);
textViewUserName = (TextView) itemView.findViewById(R.id.textView_user_name);
imageButtonCheckMark = (ImageButton) itemView.findViewById(R.id.imageButton_add_user);
}
}
Adapter class
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ListViewHolder> {
private LayoutInflater inflater;
private Context context;
private List<Metadata> list;
public static boolean isUserSelected = false;
ListInterface listener;
public ListAdapter(Context context, List<Metadata> data, ListInterface listener) {
Log.d(TAG, "Passed list to adapter : " + data.size());
inflater = LayoutInflater.from(context);
this.context = context;
this.list = data;
this.listener = listener;
}
#Override
public ListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.item_following_people, parent, false);
return new ListViewHolder(view);
}
#Override
public void onBindViewHolder(ListViewHolder holder, int position) {
holder.textViewUserName.setText(list.get(position).name);
holder.imageButtonCheckMark.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!isUserSelected) {
holder.imageButtonCheckMark.setImageResource(R.drawable.checkmark_green);
isUserSelected = true;
} else {
holder.imageButtonCheckMark.setImageResource(R.drawable.checkmark_grey);
isUserSelected = false;
}
listener.onUserSelected(isUserSelected, holder.getLayoutPosition());
}
});
}
#Override
public int getItemCount() {
return list.size();
}
}
Inteface class
public interface ListInterface {
public void onUserSelected(boolean userStatus, int listPosition);
}
Interface callback listener inside activity
// Interface callback listener implemented in the activity class
private ArrayList<Metadata> metadataList = new ArrayList<>();
ArrayList<String> selectedUserIdList = new ArrayList<>();
#Override
public void onUserSelected(boolean isUserSelected, int pos) {
if (isUserSelected) {
Log.d(TAG, "Selected user Id: " + metadataList.get(pos).userID);
followersSelectedIdList.add(metadataList.get(pos).userID);
} else {
Log.d(TAG, "Removed user Id: " + metadataList.get(pos).userID);
followersSelectedIdList.remove(metadataList.get(pos).userID);
}
}
Add one attribute in your model class that will save the state as your button is selected or not, write code in onBindViewHolder() to manage button view like this,
if(yourModel.getIsSelected()){
// positive view
} else {
//negative view
}
You see this behavior because views are reused (recycled) as you scroll. You need to save the state for all buttons in the list and set the state on each button in onBindViewHolder() as it becomes visible.
I am creating an application. When user clicks on edit button I want to check for the user and enable editing of if the same user is the owner of the comment.
I am able to check for the user. But my problem is when user clicks on edit button of one comment, many comments become editable instead of one. I am not getting how to come out of this issue. All suggestions are welcome.
below is my adapter code:
public class ToadlineCommentAdapter extends RecyclerView.Adapter<ToadlineCommentAdapter.MyViewHolder> {
private ClickListener clickListener;
private SwipeRefreshLayout.OnRefreshListener clickListener1;
private LayoutInflater inflater;
String newEnteredCommentText, neededCommentId, text;
ArrayList<String> postCreatorId;
ArrayList<String> postIdForComments;
HttpURLConnection conn;
String userId;
int clickedPosition;
Context mContext;
ArrayList<String> commentId;
List<CommentDataStore> data = Collections.EMPTY_LIST;
private String userCredentials = "toadwaysIfocus:toadwaysIfocus";
private String basicAuth = "Basic " + new String(Base64.encode(userCredentials.getBytes(), 0));
public ToadlineCommentAdapter(Context context, List<CommentDataStore> data, ArrayList<String> commentId, ArrayList<String> postCreatorId, String userId, ArrayList<String> postIdForComments ) {
inflater = LayoutInflater.from(context);
this.data = data;
this.commentId = commentId;
mContext = context;
this.postCreatorId = postCreatorId;
this.userId = userId;
this.postIdForComments = postIdForComments;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_comment_layout, parent, false);
MyViewHolder viewHolder = new MyViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
CommentDataStore current = data.get(position);
Picasso.with(mContext)
.load(current.commentProfileImageLink)
.placeholder(R.mipmap.human_image)
.into(holder.commentImage);
holder.commentUserName.setText(current.commentUserName);
holder.commentDays.setText(current.commentDays);
holder.commentDescription.setText(current.commentDescription);
holder.commentAgreeCount.setText(current.commentAgreeCount);
holder.commentDisAgreeCount.setText(current.commentDisAgreeCount);
}
#Override
public int getItemCount() {
return data.size();
}
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
public void setClickListener1(SwipeRefreshLayout.OnRefreshListener clickListener1) {
this.clickListener1 = clickListener1;
}
// View Holder object for Recycler View
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener {
TextView commentUserName, commentDays, commentAgreeCount, commentDisAgreeCount;
EditText commentDescription;
ImageView commentImage;
ImageButton commentEdit, commentDelete;
Button commentEditSubmit;
public MyViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener((View.OnClickListener) this);
commentImage = (ImageView) itemView.findViewById(R.id.imageViewUser);
commentUserName = (TextView) itemView.findViewById(R.id.textViewTitle);
commentDays = (TextView) itemView.findViewById(R.id.textViewNoOfDays);
commentDescription = (EditText) itemView.findViewById(R.id.textViewCommentDescription);
commentAgreeCount = (TextView) itemView.findViewById(R.id.textViewAgreeCount);
commentDisAgreeCount = (TextView) itemView.findViewById(R.id.textViewDisAgreeCount);
commentEdit = (ImageButton) itemView.findViewById(R.id.imageButtonCommentEdit);
commentDelete = (ImageButton) itemView.findViewById(R.id.imageButtonCommentDelete);
commentEditSubmit = (Button) itemView.findViewById(R.id.commentEditSubmit);
commentDescription.setEnabled(false);
commentEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int clickedPosition = getAdapterPosition();
if (postIdForComments.get(clickedPosition).equals(userId)){
commentDescription.setEnabled(true);
commentDescription.setBackgroundColor(mContext.getResources().getColor(R.color.colorHighlight));
commentEditSubmit.setVisibility(View.VISIBLE);
neededCommentId = commentId.get(clickedPosition);
}
else {
Toast.makeText(mContext, mContext.getResources().getString(R.string.comment_not_editable), Toast.LENGTH_SHORT).show();
return;
}
}
});
}
#Override
public void onClick(View view) {
if (clickListener != null) {
clickListener.itemClicked(view, getPosition());
}
}
#Override
public void onRefresh() {
onClick(itemView);
}
public interface ClickListener {
public void itemClicked(View view, int position);
}
}
For example if I click edit button in 5th card row I want only 5th card row to be allowed to edit. currently edit buon for 10th or 14th row will get automatically selected. Why is this happening?
The views are being recycled. In onBindViewHolder() you need to reset them to their initial state.
EDIT
RecyclerView recycles views. When one of it's children scrolls far enough off screen, the child is detached and placed in a pool of recycled/reycleable views. When the RecyclerView needs a new child to show, it can take a view from this pool (instead of instantiating from scratch) and simply bind new data to the view -- in other words, it won't call onCreateViewHolder(), but it will call onBindViewHolder().
When you click the edit button, you change the state of some views in the ViewHolder. Then you scroll until it's recycled, but it keeps all this state that it had before. You need to return these views to their initial state inside of onBindViewHolder() to handle this.
You should use SparseBooleanArray.
Look at this code and try to do this.
SparseBooleanArray mArray;
now define its size.
mArray = new SparseBooleanArray(yourArray.size());
now perform onClick
commentEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int clickedPosition = getAdapterPosition();
if (postIdForComments.get(clickedPosition).equals(userId)){
mArray.put(clickedPosition,true);
}else {
Toast.makeText(mContext, mContext.getResources().getString(R.string.comment_not_editable), Toast.LENGTH_SHORT).show();
return;
}
}
});
And finally in your onBindViewHolder.
if(mArray.get(position) == true){
commentDescription.setEnabled(true);
commentDescription.setBackgroundColor(mContext.getResources().getColor(R.color.colorHighlight));
commentEditSubmit.setVisibility(View.VISIBLE);
neededCommentId = commentId.get(clickedPosition);
}else if(mArray.get(position) = true)){
}
I hope this will help you.
Edit :
You should initialize your SparseBooleanArray in your Adapter rather then ViewHolder.
I am trying to code my own recyclerview slector algorithm. So far, I successfully managed to code that partially except handling the first selection. Basically I want to set background as blue for selected item, white elsewhere (same as ListView's setSelection).
So, the idea is:
Set Blue background for the first element in Adapter's onCreateViewHolder method.
In ActivityMain, define an intance View variable navMenuSelection to store current selection
In recyclerView's onclick listener, set the background of clicked view to blue, background of navMenuSelection as white, and update navMenuSelection to clicked view
All is working except:
1. Can't initialize navMenuSelection with the first view. Tried to use mDrawerLayout.getChildAt(0) at onPostCreate method, but returns null
How to pass the view navMenuSelection in savedInstanceState bundle?
Any idea will be highly appreciated.
public class ActivityMain extends AppCompatActivity {
private View navMenuSelection = null; // Select current view
protected void onCreate(Bundle savedInstanceState) {
// ALL THE CODES TO DEFINE RECYCLERVIEW
mRecyclerView.addOnItemTouchListener(new RecycleTouchListener(this, new ClickListner() {
#Override
public void onClick(View view, int position) {
if(view != navMenuSelection){
setNavItemSelected(view);
removeNavItemSelected(navMenuSelection);
navMenuSelection = view;
mDrawerLayout.closeDrawers();
}
}
}));
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
navMenuSelection = mDrawerLayout.getChildAt(0);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState){
//savedInstanceState.put???("currselection", navMenuSelection); // HOW TO DO THAT
super.onSaveInstanceState(savedInstanceState);
}
public void setNavItemSelected(View v){
if(v!= null) {
v.setBackgroundColor(R.color.BLUE));
}
}
public void removeNavItemSelected(View v){
if(v!= null) {
v.setBackgroundColor(R.color.WHITE));
}
}
}
Adapter Class (after moving onClick event to adapter)
public class NavDrawerAdapter extends RecyclerView.Adapter<NavDrawerAdapter.ViewHolder> {
private String[] mNavTitles; // stores title
private int[] mIcons; // stores icon
private Context context;
private int oldpostion = 0;
public NavDrawerAdapter(Context context, String Titles[], int[] Icons){
this.context = context;
mNavTitles = Titles;
mIcons = Icons;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
public ViewHolder (View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.title);
imageView = (ImageView) itemView.findViewById(R.id.icon);
}
}
#Override
public NavDrawerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.navdrawer_item,parent,false);
return new ViewHolder(v,viewType);
}
#Override
public void onBindViewHolder(NavDrawerAdapter.ViewHolder holder, final int position) {
holder.textView.setText(mNavTitles[position]);
holder.imageView.setImageResource(mIcons[position]);
if(position == 0) {
setNavItemSelected(holder.itemView);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(position != oldpostion){
setNavItemSelected(v);
//removeNavItemSelected(OLD VIEW);
oldpostion = position;
}
}
});
}
#Override
public int getItemCount() {
return mNavTitles.length;
}
#Override
public int getItemViewType(int position) {
return 1;
}
public void setNavItemSelected(View v){
if(v!= null) {
v.setBackgroundColor(context.getResources().getColor(R.color.navdrawer_item_selected_bg));
TextView tview = (TextView) v.findViewById(R.id.title);
tview.setTextColor(context.getResources().getColor(R.color.navdrawer_item_selected_text));
}
}
public void removeNavItemSelected(View v){
if(v!= null) {
v.setBackgroundResource(R.drawable.list_selector_nav_drawer);
TextView tview = (TextView) v.findViewById(R.id.title);
tview.setTextColor(context.getResources().getColorStateList(R.color.list_selector_nav_drawer_text));
}
}
}
As for your questions:
To get a view you need in the RecyclerView you can use mRecyclerView.findViewHolderForAdapterPosition(position).
I may be wrong but I think you only need to save the position of the view, not the view itself, which is just int.
Another pattern, I used before, is adding a boolean array to your RecyclerView.Adapter that saves the info about what view(s) (associated with a position in your data collection) should be activated in the moment. Based on this array I was changing background of views in onBindViewHolder().
Your current solution is ok if the recycler view is short enough to be seen on a single screen. But as soon as it starts recycling its old viewholders you'll get "selected" background reused as well on not selected views - all because you remembered views, rather than data positions connected to them.
EDIT
I'll put here some relevant code from the adapter to illustrate my idea on implementation. In my approach I used a state list drawable with "selected" background for the activated state, but you can do all the same by manually setting the background.
public class RecyclerAdapter
extends RecyclerView.Adapter<RecyclerAdapter.YourViewHolder> {
private final List<...> data;
private final RecyclerAdapterCallbacks listener; //e.g. for activity callbacks
private final List<Boolean> activation;
public RecyclerAdapter(List<...> data, RecyclerAdapterCallbacks listener) {
this.data = data;
this.listener = listener;
this.activation = new ArrayList<>(data.size());
fillActivationList();
}
private void fillActivationList() {
int size = data.size();
for (int i = 0; i < size; i++) activation.add(false);
}
//------YourViewHolder implementation here------
public interface RecyclerAdapterCallbacks { //Callbacks interface if needed
void onRowSelected(... dataPiece);
void onRowDeselected();
}
#Override
public WordsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//your code
}
#Override
public void onBindViewHolder(YourViewHolder holder, final int position) {
holder.field.setText(data.get(position).getString());
holder.itemView.setActivated(activation.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Boolean previousState = activation.get(position);
deactivateAll();
activation.set(position, !previousState);
notifyDataSetChanged();
if (!previousState) {
listener.onRowSelected(data.get(position));
} else {
listener.onRowDeselected();
}
}
});
}
private void deactivateAll() {
Collections.fill(activation, false);
}
#Override
public int getItemCount() {
return data.size();
}
public void clearResults() {
notifyItemRangeRemoved(0, data.size());
data.clear();
activation.clear();
}
public void add(Word item) {
data.add(item);
notifyItemInserted(data.size() - 1);
activation.add(false);
}
Since you are already using array to pass your icon and title, let's add another array to save your current selection
private boolean isSelected[] = {true, false, false, false, false}; //make sure that the length of this array matches the length of navtitles and navicon. set the first element to true since you want the first item to be selected by default. you can declare this directly on the adapter if this is static
or you can pass it as a parameter
private boolean isSelected[];
public NavDrawerAdapter(Context context, String Titles[], int[] Icons, boolean[] isSelected){
this.context = context;
mNavTitles = Titles;
mIcons = Icons;
this.isSelected = isSelected;
}
....
#Override
public void onBindViewHolder(NavDrawerAdapter.ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i < isSelected.length(); i++){
if (i==position){
isSelected[position]=true;
else
isSelected[position]=false;
}
notifyDataSetChanged();
}
});
if (isSelected[position]==true){
//execute your codes here
}else{
//execute your codes here
}
}
just try to debug if there's any error or typo. i did not use any code editor for this so there may be some error
To make it easier for you, I suggest just adding the layout in your viewholder so you can just change the background of the layout. not the cleanest method but this one should do the trick for you
public class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
LinearLayout layout; //whatever layout your using, just an example
public ViewHolder (View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.title);
imageView = (ImageView) itemView.findViewById(R.id.icon);
layout = (LinearLayout) itemView.findViewById(R.id.layout);
}
}
...
#Override
public void onBindViewHolder(NavDrawerAdapter.ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i < isSelected.length(); i++){
if (i==position){
isSelected[position]=true;
else
isSelected[position]=false;
}
notifyDataSetChanged();
}
});
if (isSelected[position]==true){
//execute your codes here
holder.layout.setBackgroundResource(R.drawable.list_selector_nav_drawer);
holder.textView.setTextColor(context.getResources().getColorStateList(R.color.list_selector_nav_drawer_text));
}else{
//execute your codes here
holder.layout.setBackgroundResource(R.drawable.list_selector_nav_drawer);
holder.textView.setTextColor(context.getResources().getColorStateList(R.color.list_selector_nav_drawer_text));
}
}