RecyclerView position at the fragment level - android

I have a fragment that contains a Recyclerview (along with ViewHolder and Adapter). The onClick handler is defined inside ViewHolder, but I would like to query the position of item selected in the fragment level.
I can save the item position to fragment's member variable using getAdapterPosition() from within the ViewHolder's onClick but is there a direct way to get the ViewHolder or position clicked from the fragment level? Ideally I would rather the ViewHolder not know anything about the fragment.

You could use multiple listeners (interfaces) to transport the clicked position back from your ViewHolders to your Fragment via your RecyclerView. Following is a minimalized example of what I mean: basically you let your Fragment listen to your RecyclerView, which in turn listens to your ViewHolders beeing clicked.
Hope this helps you find a way to solve your problem. Don't know if it is the best way, but it worked for me and I like this communication.
YourViewHolder.java
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick() {
for (ViewHolderListener l : listeners) {
l.onViewHolderClicked(getLayoutPosition())
...
public interface ViewHolderListener() {
void onViewHolderClicked(int position);
}
YourRecyclerView.java
public class YourRecyclerView ... implements YourViewHolder.ViewHolderListener {
...
#Override
public void onViewHolderClicked(int position) {
for (RecyclerViewListener l : listeners) {
l.onViewClicked(position);
...
public interface RecyclerViewListener {
void onViewClicked(int position);
}
YourFragment.java
public class YourFragment ... implements YourRecyclerView.RecyclerViewListener {
...
#Override
public void onViewClicked(int position) {
// Here you do whatever you want with the clicked view's position
}

Related

Update TextView in Fragment when RecyclerView's data changes

In my Fragment, I have 2 views. A Textview and a RecyclerView. The Textview essentially displays the current size of the RecyclerView. So, when a row is removed in the adapter class, I need to update the TextView's value accordingly.
The row is removed successfully when removeBtn is clicked, but I need to update the TextView in the Fragment accordingly.
FRAGMENT
titleText.text = "SIZE (" + arrayStringList().size.toString() + ")"
//...
//...
//Set RecyclerView Adapter
mRecyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
val adapter = MRecyclerView(context!!, arrayStringList)
mRecyclerView.adapter = adapter
RECYCLERVIEW
holder.removeBtn{
mData.removeAt(position)
notifyItemRemoved(position)
}
Is there some sort of listener that I can put in my fragment to detect when the data changes? Or is there a way to send data from the recyclerview back to the fragment when removeBtn is clicked?
Create a interface in recyclerView class , and implement that interface in fragment . Once you click the remove button , call this interface . In Fragment class , update the text view with adapter.getItemCount.
In Adapter
interface ItemCallback{
void updateTextView();
}
This interface will be implemented in fragment class ,where you can update your textView with itemCount .
public class Fragment implements Adapter.ItemCallback{
#Override
public void updateTextView() {
tvTextView.setText(adapter.getItemCount()); // This will return the current item count of adapter
}
}
You can do this via call back. Make an interface and implement that on Fragment. And pass the reference of the interface to the adapter. When you trigger the event to delete item from recycler view call the interface method (That you implemented on Activity). And in that call back method, you need to set the value to your text view. To set value on TextView, you can call size() method and set the value whatever is returned from it. For example the List you are passing to the adapter is mData. When you get call back the call size method on the reference and set the value as mentioned below code.
titleText.setText(String.valueOf(mData.size())).
Hope this will help you.
NOTE: You need to call String.valueOf method because size method returns integer value so it needs to be cast.
"Or is there a way to send data from the recyclerview back to the fragment when removeBtn is clicked?" the answer is yes
One approach is to pass your adapter your own click listener (an interface), this way you can control the click from the fragment something like this,
A1) create an interface
public interface ItemTouchListener {
void onCardClick(View view, int position);
boolean onCardLongClick(View view, int position);
}
A2) implement this interface in your fragment
public class YourFragment extends Fragment implements ItemTouchListener
A3) implement the methods you created in your fragment
#Override
public void onCardClick(View view, int position) {
if (view.getId() == R.id.removeBtn){
//update your text
}else{
//other buttons
}
}
#Override
public boolean onCardLongClick(View view, int position) {
if (view.getId() == R.id.removeBtn){
//update your text
} else {
//other buttons
}
return true;
}
A4) create this interface in your adapter and set it to your button
private ItemTouchListener onItemTouchListener;
public YourAdapter(List<Object> list, ItemTouchListener onItemTouchListener) {
this.onItemTouchListener = onItemTouchListener;
this.list = list;
}
removeBtn = view.findViewById(R.id.removeBtn);
removeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemTouchListener.onCardClick(v, getAdapterPosition());
}
});
removeBtn.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
onItemTouchListener.onCardLongClick(view, getAdapterPosition());
return true;
}
});
A5) and now when you create your adapter it will ask for the ItemTouchListener which you can give it by just passing 'this'
YourAdapter adapter = new YourAdapter(this);
A6) you may also want to give your adapter a method something like getCount which return the list size
public int getCount(){
list.size();
}
and then you can call this like myAdapter.getCount

How to call clicklistener of an item's textview inside a recyclerview outside the adapter?

I have recyclerview inside an activity. I have some View inside each item. Suppose a textview, I am implementing a click listener on that particular view.
However, there is a case where i have to call the clicklistener of a particular position of that textview.
Since there is no function to call the onclick where i can pass the position.
I thought holder.itemview.callonclick() would work. But it is not working.
is there any way to call the itemview's textview of a particular position of a recyclerview.
You can create custom click listener using interface like below.
public interface ClickInterface {
public void recyclerviewOnItemClick(int position);
}
make sure you implement this interface to class where you want your code to be executed and implement it's method.Then you can pass this listerer's refrence to adapter like this.
TestAdapter adapetr = new TestAdapter (this);
listview.setAdapter(adapter);
In adapter :
private ClickInterface clickInterface;
public TestAdapter (ClickInterface clickInterface) {
this.clickInterface = clickInterface;
}
viewHolder.txtview.setOnClickListener(v ->
clickInterface.recyclerviewOnItemClick(position));
-You will get implemented method call when textview is being clicked.
You can try like this in Holder class,
mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getAdapterPosition()== YOUR_POS)
{
code..
}
}
});
or in onBindViewHolder ,`
if(i==YOUR_POS){ holder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
code..
}
});}

How to access RecyclerView viewholder inside main activity in android?

I have a list in activity with dynamic data.When i click on a button inside list item,I want to hide any text from list item.From adapter class it can be possible to get views from custom layout but from activity how to do this?
Just change the data of that particular position and then call YourCustomUpdateFunc:
//Function inside your RecyclerAdapter class
public void YourCustomUpdateFunc(int pos){
notifyItemChanged(pos);
}
Then, the onBindViewHolder function will do its work.
First Create local Variable in adapter class as
OnCustClick mclickListner;
then in viewholder override method like
#Override
public void onClick(View v) {
if (mclickListner != null) {
mclickListner.onItemClick(v, getAdapterPosition());
}
}
after that add this methods in your adapter class
public interface OnCustClick{
void onItemClick(View view, int position);
}
public void setOnCustClick(OnCustClick mclickListner)
{
this.mclickListner = mclickListner;
}
and in activity implement interface

RecyclerView onItemClick Interface: get values in the Adapter or in the Activity?

I have a ViewHolder with an OnClickListener, which sends the click over an Interface to the underlying Activity. The only information i send is the AdapterPosition. In the Activity i then get the information out of the Activitie's reference to the ArrayList (which also fills the Adapter), using the position i get passed from the Adapter. I then use this to open a new Activity where i show this data.
Now, this works, but i just came to mind that this could cause problems, if i don't properly call notifyDataSetChanged/ItemInserted/Removed etc. and the Adapter shows a different List than the actualy up-to-date List in the Activity. I am right about this? Should i get the values out of the Objects IN the Adapter and pass them to the Activity or is my approach correct?
ViewHolder:
public class ExampleViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public TextView mTextViewCreator;
public TextView mTextViewLikes;
public ExampleViewHolder(View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.image_view);
mTextViewCreator = itemView.findViewById(R.id.text_view_creator);
mTextViewLikes = itemView.findViewById(R.id.text_view_likes);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
mListener.onItemClick(position);
}
}
}
});
}
}
MainActivity OnItemClick implementation:
#Override
public void onItemClick(int position) {
Intent detailIntent = new Intent(this, DetailActivity.class);
ExampleItem clickedItem = mExampleList.get(position);
detailIntent.putExtra("imageUrl", clickedItem.getImageUrl());
detailIntent.putExtra("creatorName", clickedItem.getCreator());
detailIntent.putExtra("likeCount", clickedItem.getLikeCount());
startActivity(detailIntent);
}
The answer is simple: Always make sure that you notify the adapter about changes.
Otherwise its behavior becomes unpredictable.
Apart from that, your code seems to be fine
My personal preference is that you send the model to the activity, that's what it's interested in, it doesn't care about your adapter position, and even if in the future your list became an expandable list or even a ViewPager, all the Callback (Activity) wants is the model to start the new screen.
You can change your listener method to
onItemClick(ExampleItem item)
and then you can set your listener when onBindViewHolder is called.

Android create interface listener for onClick in Adapter

in my application i'm create simple interface to detect after click on adapter items into parent activity.after create interface and method into adapter i can not how to use this interface to call listener, for example:
Interface Class:
public interface IOnClickListListener {
public void onClick(boolean click);
}
summurized Adapter:
private static class ViewHolder {
public ViewHolder(View view) {
}
public void fill(final ArrayAdapter<SubjectListStructure> adapter, final SubjectListStructure item, final int position) {
root.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/* call interface to listen that */
}
});
}
}
public void setOnClickListener(IOnClickOnNiyazmandihaListListener l){
iOnClickOnNiyazmandihaListListener = l;
}
in this adapter after click on item, my interface must be call. now i want to listen that into activity by this code:
subjects_adapter.setOnClickListener(new IOnClickOnNiyazmandihaListListener() {
#Override
public void onClick(boolean click) {
Toast.makeText(G.currentActivity,"ddddd", Toast.LENGTH_SHORT).show();
}
});
now how to call listener into adapter ?
if you want to trigger/invoke the callback, simply call
boolean click = true
iOnClickOnNiyazmandihaListListener.onLogin(click)
from the adapter class
In my honest opinion, if you intend to register the click event inside an adapter, you must pass the position of item which was clicked, instead of passing a boolean value to check if item was clicked or not. In this way, you will get a number of options to handle the clicked item callback.
Here is a simple implementation from my side according to your use-case.
Your interface class just require a small change as follows:
public interface IOnClickListListener {
public void onClick(int positionOfItem);
}
Inside your adapter class, at the onClick() of your root's setOnClickListener, you must call the interface's method in the following way, considering iOnClickOnNiyazmandihaListListener is a member variable of your adapter class
iOnClickOnNiyazmandihaListListener.onClick(position)
where position is passed as a parameter to setOnClickListener and it is the actual position of item clicked.
In this way, wherever you want this onClick() method to be called, you have to provide implementation of the interface in that class, about what you want to do with the clicked position when onClick() is triggered.
So whenever any list item is clicked, your custom implementation of the onClick() method will be used, and the code which you put inside that implemented method will be called.
Example:
Suppose you implemented this interface in an activity, then it tell you to override the onClick() method of your interface inside that activity, i.e. to provide onClick() implementation
So implementation of onClick() would look similar as follows:
#Override
void onClick(int position){
// do what you want to do with clicked item's position
Toast.makeText(this, "Item at position:" + position + " clicked", Toast.LENGTH_LONG).show();
}
For that, your class must have implements IOnClickOnNiyazmandihaListListener as its starting line.

Categories

Resources