Got stuck on this problem for few days hope to find the solution.
I am unable to pass the data written on the card (Card View) to the next activity.
For clicking card, I am implementing its onClickListner in its recyclerView Adapter.
I want to pass the position of the card clicked but since card View does not support onItemClickListner I am facing the problem.
RecyclerViewAdapter class
public class RVAdapter extends recyclerView.Adapter<RVAdapter.PersonViewHolder> implements View.OnClickListener, View.OnLongClickListener {
int position;
#Override
public void onBindViewHolder(PersonViewHolder holder, int i) {
setEventsForViews(holder, i);
}
private void setEventsForViews(PersonViewHolder holder, int i) {
position = i;
holder.cv.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Navigator.toAddFriends(context, placeList.get(getPosition()).getPlaceId());
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cv;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cv);
}
}
I tried to set up a variable position and tried to pass its value but since onBindViewHolder is called intially for all items in the view and I end up in setting the value of position as last one. I know this is the wrong approach but as I am new to this card View thing please suggest me any good and clean way to do this.
Thanks in advance.
Create a new interface, like:
public interface RecyclerViewClickListener {
public void recyclerViewListClicked(View v, int position);
}
On your Fragment/Activity, implement the new interface:
public class MyFragment extends BaseFragment implements RecyclerViewClickListener { }
Now, you will be forced to implement the interface method recyclerViewListClicked(View v, int position) on your Fragment/Activity.
Do that so you can do whatever you want when one item is clicked. Do it like so:
#Override
public void recyclerViewListClicked(View v, int position) {
myList.get(position);
}
Now lets go to your Adapter.
On your adapter constructor, add a new listener parameter. It's type is the interface we have just created (don't forget to create a private static listener and set it on your constructor):
private static RecyclerViewClickListener mListener;
public myListAdapter(List<Thing> things, final Context context, RecyclerViewClickListener itemClickListener) {
mThings = things;
mContext = context;
mListener = itemClickListener;
}
Inside your adapter, on your ViewHolder, implement View.OnClickListener like:
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
You will now be forced do #Override the onClickMethod inside your ViewHolder. Do it:
#Override
public void onClick(View v) { }
On your ViewHolder constructor, set the onClickListener of your view. Like:
public MyViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
myCardViewLayout.setOnClickListener(this);
}
Now implement the behaviour to your ViewHolder onClickMethod. In this case, I call the recyclerViewListClicked method of the static listener we declared in our adapter. This method is the one we have #Overriden in our fragment/activity, so it requires the position parameter.
Get the position by calling getLayoutPosition() inside your view holder. It will look like this:
#Override
public void onClick(View v) {
mListener.recyclerViewListClicked(v, getLayoutPosition());
}
Finally, get back to your fragment/activity, and pass the listener to the adapter constructor with this (since now we implement the interface RecyclerViewClickListener it can just pass itself as a listener to the adapter):
mRecyclerView.setAdapter(new MyListAdapter(this.mList, this.getActivity(), this))
Now, when you click on a myCardViewLayout on your list items it's going to call the recyclerViewListClicked(View v, int position) of your Fragment/Activity and you will be able to work with the position parameter as you'd like.
You can do this to any layout you want to get a click event from inside your list. Just replace myCardViewLayout.setOnClickListener(this) inside your ViewHolder constructor with myDesiredToHaveOnClickListenerLayout.setOnClickListener(this).
Hope this helps.
#EDIT:
Some tips:
Remove implements View.OnClickListener, View.OnLongClickListener from your adapter.
And looks like you don't need to call setEventsForViews(holder, i) on your onBindViewHolder anymore. Confirm?
#UPDATE
This is how your ViewHolder will look like:
public static class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
CardView cv;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cv);
cv.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mListener.recyclerViewListClicked(v, getLayoutPosition());
}
}
Related
I have a RecyclerView with some images,here i want to open different Activitys by clicking on different images...
So, i think using the switch statement in the onClick of the adapter will solve my problem but i don't know how to add a switch-if statement in a RecyclerView adapter.i am a beginer in android development so i need some help...
myadapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ImageViewHolder> {
#NonNull
private int[] images;
public RecyclerAdapter(int[] images){
this.images =images;
}
#Override
public ImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item2,parent,false);
ImageViewHolder imageViewHolder = new ImageViewHolder(view);
return imageViewHolder;
}
#Override
public void onBindViewHolder(#NonNull ImageViewHolder holder, int position) {
int image_id =images[position];
holder.imagess.setImageResource(image_id);
}
#Override
public int getItemCount() {
return images.length;
}
public static class ImageViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView imagess;
TextView titless;
public ImageViewHolder(View itemView) {
super(itemView);
imagess = itemView.findViewById(R.id.image);
titless = itemView.findViewById(R.id.title);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// Toast.makeText(itemView.getContext(), "DOWNLOAD ANY TORRENT DOWNLOADER AND OPEN", Toast.LENGTH_LONG).show();
}
}}
So what i want is :
I want to open different activities if the user click the cat image,it should open a activity named cats and if the user clicks the dog image it should open a activity named dogs ...
#Override
public void onClick(View v) {
switch(getAdapterPosition()) {
case 0:
Intent intent = new Intent(context, Cat.class);
context.startActivity(intent);
break;
case 1: // Open second activity
};
}
Returns the Adapter position of the item represented by this ViewHolder.
I have very little experience with Java, I write only in Kotlin. Here is what I have come up with.
Setting the click-events within the Adapter itself is not the best practise.According to the recommended way you should add a callback method and let the Activity
\ Fragment to which the Recycler is attached handle after the click events.
How to Proceed,
Step 1: Create an Interface which loosely binds your Adapter to Activity or Fragment.
interface AdapterListener{
void afterAdapterItemClicked(int adapterPosition);
}
This Interface can be created within Adapter itself as an inner member.
Step 2: Let the Activity or Fragment to which the Recycler is attached implement this Interface,So let assume your Activity is named as MenuActivity
class MenuActivity extends Activity implements AdapterListener{
}
Step 3: Now inside the Activity / Fragment implement the override method
#Override
void afterAdapterItemClicked(int adapterPosition){
switch(adapterPosition) {
case 0: // Move to activity1
break;
case 1: // Move to activity2
break;
}
}
Step 4 : Now calling the method afterAdapterClicked() after the click event
public static class ImageViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
ImageView imagess;
TextView titless;
public ImageViewHolder(View itemView) {
super(itemView);
imagess = itemView.findViewById(R.id.image);
titless = itemView.findViewById(R.id.title);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mListener.afterAdapterItemClicked(getAdapterPosition());
}
}
Step 5: Now to all the curious faces thinking, where in the world mListener landed from, don't worry I saved it for the last.
Now when you create the RecyclerAdapter object(instance) inside your Activity / Fragment you need to pass the current context or this in its constructor.
RecyclerAdapter(arrayOfImages,this);
Now create a new state variable inside your RecyclerAdapter class such as
private AdapterListener mListener;
And then in the constructor of RecyclerAdapter you need to add a variable of type
AdapterListener like this and then assign mListener the received value
public RecyclerAdapter(int[] images,AdapterListener mListener){
this.images = images;
this.mListener = mListener;
}
And then use mListener inside your inner class ImageViewHolder.
I'm looking the answer how to make onClickListener button located in Recycleview Item using Butterknife. I know how to do it without Butterknife, but I can't find anything with Bt.
Does Bt supports this?
' class ViewHolder {
#BindView(R.id.title) TextView name;
#BindView(R.id.job_title) TextView jobTitle;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
#OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
}'
Try to learn from the sample code at official site
If you want to implement the click logic in the activity then here are the steps.
1 Create an interface
public interface ClickHandler{
void onClick(int position);
}
2 Implement CLickHandler in activity
MainActivity extends AppCompatActivity implements ClickHandler{
...
public void onclick(int position){
Log.d("Check","Clicked at" + position);
}
...
adapter = new MyAdapter(this);//Pass the reference to activity as it implements the clickhandler.
...
}
3 Now your adapter has the reference for clickhandler. Similarly pass it to the viewholder and call the onCLick method from there.
class ViewHolder {
#BindView(R.id.title) TextView name;
#BindView(R.id.job_title) TextView jobTitle;
ClickHandler clickHandler;
public ViewHolder(View view, ClickHandler) {
ButterKnife.bind(this, view);
this.clickHandler = clickHandler;
}
#OnClick(R.id.submit)
public void submit(View view) {
if(clickHandler(!=null){
clickHandler.onClick(getAdapterPosition());
}
}
}
i am working on a notapad like android app project. i which i have implemented recycler.
My project contains NotedAdaper class that extends RecyclerView.Adapter<NotesAdapter.ViewHolder>
in that class using the below code i used click listener,
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.ViewHolder> {
private List<Notes> mNotes;
private Context mContext;
public NotesAdapter(Context context, List<Notes> notes) {
mNotes = notes;
mContext = context;
}
#Override
public NotesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View notesView = inflater.inflate(R.layout.items_notes, parent, false);
// Return a new holder instance
ViewHolder viewHolder = new ViewHolder(notesView);
return viewHolder;
}
// Easy access to the context object in the recyclerview
private Context getContext() {
return mContext;
}
#Override
public void onBindViewHolder(NotesAdapter.ViewHolder viewHolder, final int position) {
// Get the data model based on position
Notes notes = mNotes.get(position);
// Set item views based on your views and data model
TextView textView = viewHolder.preTitle;
textView.setText(notes.getTitle());
TextView textView1 = viewHolder.preText;
textView1.setText(notes.getText());
String color=notes.getColor();
CardView preCard=viewHolder.preCard;
preCard.setBackgroundColor(Color.parseColor(color));
ImageView img = viewHolder.preImage;
img.setVisibility(View.GONE);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Notes notes = mNotes.get(position);
Intent intent = new Intent(view.getContext(),EditNote.class);
Bundle bundle = new Bundle();
bundle.putSerializable("DATA",notes);
intent.putExtras(bundle);
getContext().startActivity(intent);
Toast.makeText(getContext(), "Recycle Click" + position+" ", Toast.LENGTH_SHORT).show();
}
});
}
// Returns the total count of items in the list
#Override
public int getItemCount() {
return mNotes.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
public RobotoTextView preTitle, preText;
public ImageView preImage;
public CardView preCard;
public ViewHolder(View itemView) {
super(itemView);
preTitle = (RobotoTextView) itemView.findViewById(R.id.preTitle);
preText = (RobotoTextView) itemView.findViewById(R.id.preText);
preImage=(ImageView) itemView.findViewById(R.id.preImage);
preCard=(CardView) itemView.findViewById(R.id.preCard);
}
}}
And its absolutely working find. on clicking of a item in recycler, it retrieves the data using position of that item. and showing in another activity.
just like, suppose a activity shows the list of notes created by user. and clicking on any note, it shows the full content of that note.
but now i want to implement Long click listener on the item. and get the position.
so that, i used the following code ...
viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
Notes notes = mNotes.get(position);
Toast.makeText(getContext(), "long Click" + position+" ", Toast.LENGTH_SHORT).show();
return false;
}
});
so, its also working.
but what i want is, on long click, it should only show that Toast.
but its not only showing the long click toast. but also recognising click listener and after showing the toast>> "Long click: ..." it executing the the code written for single click event.
n i dont want it.
both listeners should work separately.
but why its executing single click after long click??? any idea???
Am i making mistake anywhere?
So, the following changes in my code, help me to achieve my output.
1) The method onBindViewHolder is called every time when you bind your view with data. So there is not the best place to set click listener. You don't have to set OnClickListener many times for the one View. Thats why, i wrote click listeners in ViewHolder, (actually that was not my question, but i read somewhere that it would be the best practice, thats why i am following it)
like this,
public static class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
public ImageView preImage;
public CardView preCard;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(final View itemView) {
// Stores the itemView in a public final member variable that can be used
// to access the context from any ViewHolder instance.
super(itemView);
itemView.findViewById(R.id.preTitle);
preImage=(ImageView) itemView.findViewById(R.id.preImage);
preCard=(CardView) itemView.findViewById(R.id.preCard);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
int p=getLayoutPosition();
System.out.println("LongClick: "+p);
return true;// returning true instead of false, works for me
}
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int p=getLayoutPosition();
Notes notes = mNotes.get(p);
Toast.makeText(getContext(), "Recycle Click" + p +" ", Toast.LENGTH_SHORT).show();
}
});
}
}
You may notice that, in onLongClick, i have returned "true", bydefault it was "false".
and this change works for me.
just make onLongClick(View v) returns return true instead of return false
this solved my problem it should solve yours too
i think you should set both the listeners from ViewHolder class.
itemView.setOnClickListener(...);
itemView.setOnLongClickListener(...);
And call getAdapterPosition() from ViewHolder to get the adapter position of the item.
You can checkout the following resource.
https://www.bignerdranch.com/blog/recyclerview-part-1-fundamentals-for-listview-experts/
I think this is an easier way to implement onClick and longClickListeners to RecyclerViews. Here's my code snippet. I've cut out unnecessary codes from here.
public class PrescriptionAdapter extends RecyclerView.Adapter<PrescriptionAdapter.ViewHolder> {
static final String TAG = "RecyclerViewAdapterMedicineFrequency";
ArrayList<Prescription> pdata;
Context context;
OnItemClickListener onItemClickListener;
OnItemLongClickListener onItemLongClickListener;
public PrescriptionAdapter(Context context, ArrayList<Prescription> presData, OnItemClickListener onItemClickListener, OnItemLongClickListener onItemLongClickListener) {
this.pdata = presData;
this.context = context;
this.onItemClickListener = onItemClickListener;
this.onItemLongClickListener = onItemLongClickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView pName, totalMeds;
ImageView pImage;
OnItemClickListener onItemClickListener;
OnItemLongClickListener onItemLongClickListener;
public ViewHolder(View itemView, OnItemClickListener onItemClickListener, OnItemLongClickListener onItemLongClickListener) {
super(itemView);
pName = (TextView) itemView.findViewById(R.id.prescriptionName);
totalMeds = (TextView) itemView.findViewById(R.id.totalMeds);
pImage = (ImageView) itemView.findViewById(R.id.prescriptionImage);
this.onItemClickListener = onItemClickListener;
this.onItemLongClickListener = onItemLongClickListener;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(getAdapterPosition());
}
#Override
public boolean onLongClick(View v) {
onItemLongClickListener.onItemLongClick(getAdapterPosition());
return true;
}
}
public interface OnItemClickListener {
void onItemClick(int i);
}
public interface OnItemLongClickListener {
void onItemLongClick(int i);
}
}
1) Problem
I would like to set 2 listeners on 2 buttons inside a CardView. I need to know which item has been selected. I use CardView with RecyclerView and FirebaseRecyclerAdapter (RecyclerView.Adapter)
2) Old Situation
I have created the listener in populateViewHolder() of my FirebaseRecyclerAdapter like this:
#Override
protected void populateViewHolder(final ItemViewHolder viewHolder, final Item model, final int position) {
viewHolder.firstButton.setOnClickListener(new View.OnClickListener() {
Item selectedItem = getItem(position);
//do something for the item selected
}
}
this works fine!
3) What I would like to do
Set listeners in the ViewHolder class (defined in his own file) and do something on the selected ITEM
I would like to set the listeners in the ViewHolder class because the same ViewHolder is used for different adapters and I think it's a better approach to have the behaviour of the listeners defined in only one place.
I did like this:
public class ItemViewHolder extends RecyclerView.ViewHolder {
public CardView cardView;
public TextView itemText;
public ImageView itemFirstButton;
public ImageView itemSecondButton;
public ItemViewHolder(View itemView) {
super(itemView);
cardView = (CardView)itemView.findViewById(R.id.item_card_view);
itemText = (TextView)itemView.findViewById(R.id.item_text);
itemFirstButton = (ImageView)itemView.findViewById(R.id.ic_first_action);
itemSecondButton = (ImageView)itemView.findViewById(R.id.ic_second_action);
itemFirstButton.setOnClickListener(firstListener);
itemSecondButton.setOnClickListener(secondListener);
}
private View.OnClickListener firstLinstener = new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
}
};
private View.OnClickListener secondListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
}
};
}
Inside the listener I can't get any reference on the item, just the position...
I have the impression I have to declare an interface for the listener and pass to the adapter, but I don't know how.
Does it make still sense to declare the listeners in the viewholder or I keep them in the adapter as the old solution?
If you want to tell your position to the adapter, just pass the some interface through ViewHolder constructor.
OR
the previous way.
The point is whom you want to delegate the position to.
Yes it is good practice to use interface. Create an interface like
public interface OnClick {
void getItem(int item);
}
Then setOnClicklistner like
itemViewHolder. itemText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
OnClick onClick = (OnClick)context;
onClick.getItem(position);
}
});
Then in your activity implement that method. From this you get position. Then by using position you get elements from array.
Hello I need help to open a new fragment and pass data when clicked on my Recycler CardView Grid.
Android Grid Image
I want to click on for example the champion Aatrox (first grid) and open a new fragment with Aatrox InformatiĆ³n. the same with the others champions of League of Legends.
I know that is inside of onClick function but I dont know how to do it.
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemView.setClickable(true);
holder.itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
}
});
Here is my full ChampAdapter.java
public class ChampAdapter extends RecyclerView.Adapter<ChampAdapter.ViewHolder> {
public List<ChampionItemModel> champItem;
public ChampAdapter(List<ChampionItemModel> champItem){this.champItem = champItem;}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView champName;
TextView roleChamp;
ImageView champImg;
public ViewHolder(View itemView) {
super(itemView);
this.champName = (TextView)itemView.findViewById(R.id.champ_name);
this.roleChamp = (TextView)itemView.findViewById(R.id.champ_role);
this.champImg = (ImageView)itemView.findViewById(R.id.champ_image);
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_champs,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemView.setClickable(true);
holder.itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
}
});
holder.champName.setText(champItem.get(position).champName);
holder.roleChamp.setText(champItem.get(position).roleChamp);
holder.champImg.setImageResource(champItem.get(position).champImg);
}
#Override
public int getItemCount() { return champItem.size();}
}
First you should embed the RecyclerView inside a fragment, like you normally would, let's call it ChampionOverviewFragment.
Now you should have a SingleChampionFragment with a static newInstance method that accepts as parameters everything that you need to build the champion information (for example a String with the id of your champ). We want to open this fragment when we click on one of the cards in your cardview.
Your activity now only has one HostFragment that you fill with the ChampionOverviewFragment in its onCreate method. See my answer on how to create nested fragments.
Your onClick method can now look like this:
#Override
public void onClick(View v){
((MainActivity) holder.itemView.getContext()).openChampionFragment(holder.getChampionId);
}
Of course, then your MainActivity has to include the following method:
public void openChampionFragment(String id)
this.hostFragment.replaceFragment(SingleChampionFragment.newInstance(id));
}
If you also need backstack navigation, refer to the tutorial I linked in the other answer.
Below is a general method on how to communicate between fragments, so it should be applicable to your issue also.
Place the recyclerView inside a fragment.
I am assuming you are able to get the position of the Adapter. Put recyclerview in a fragment call RV and it's response is to be seen in fragment say RVvalues. You use an interface called PassRVValues
Code in RV fragment:
public class RV extends Fragment{
int RVposition;
PassRVValues passRVValues;
//
your code for recyclerview and other things
//
RVposition = position_value_obtained;
passRVValues.sendToOtherFragment(RVposition);
Here's the code for the interface. Make a new java class having just the interface.
public interface PassRVValues{
sendToOtherFragment(int value_from_RVFragment);
}
Code in the activity
public class MainActivity implements PassRVValues{
//
some code
//
#Override
public void sendToOtherFragment(int use_value_from_RVFragment){
//
Do something with data if you want
//
RVvalues Frag = (RVValues)getFragmentManager().findFragmentById(R.id.rvvalues);
Frag.ShowDataBasedOnPositionInRV(something_based_from_any_process_in_sendToOtherFragment_Method);
}
Now for the code in the RVValues fragment
public class RVValues extends Fragment{
//again any codes//
public void ShowDataBasedOnPositionInRV(int data_based_on_RV_position){
//do something//
}
This is the way to implement inter-fragment communication in the simplest manner. Hope this helps!
Cheers!