So i have a parent recyclerview with vertical orientation and a child recyclerview nested with parent with horizontal orientation.
Onclick function goes with child recylerview
I have created an interface which gives the adapter position of child item back to parent adapter class.
TEST CASE
Display the recyclerview and click on any child item.
result - working fine
Scroll down the recyclerview and click on any child item.
result - working fine
Manually Scroll back to 1st position and now click on any child item.
result - parent recylerview position is -1 (FAILED TEST CASE)
What can be the possibilities of this?
If you need any code i can provide it by editing
Parent ViewHolder class
class ViewHolder extends RecyclerView.ViewHolder{
RecyclerView reClassList;
ViewHolder(View itemView, final Context context) {
super(itemView);
reClassList = itemView.findViewById(R.id.recycle_garage_list_class);
garageListEvents = new GarageListEvents() {
#Override
public void getChildPositon(int childPosition) {
// TODO Remove
Log.e("GARAGE ADAPTER","Garage List Position :"+String.valueOf(getLayoutPosition()));
}
};
}
Child ViewHolder Class
public class ClassViewHolder extends RecyclerView.ViewHolder {
public ClassViewHolder(#NonNull View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
garageListEvents.getChildPositon(getAdapterPosition());
}
});
}
}
INTERFACE
public interface GarageListEvents {
public void getChildPositon(int childPosition);
}
FYI - GarageAdapter is the parent adapter
I guess it has to do something with recycling viewholders. Try to set this to parent viewholder holder.setIsRecyclable(false);. It will have little impact on performace, but it should solve problem.
Related
I want to add an onClickListener to items in my RecyclerView. I added the listener in the Holder class as follows:
public class Holder extends RecyclerView.ViewHolder {
TextView firstName;
TextView lastName;
public Holder (final View itemView) {
super(itemView);
firstName = itemView.findViewById(R.id.firstName );
lastName= itemView.findViewById(R.id.lastName);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Do work
}
}
}
But, I think this will cause the scrolling of the list to be a little jerky and not perfectly smooth specially on old devices.
Question 1:
Is there a better way to do that? Or how can I optimize my code?
Question 2:
I intend to add a dynamically changing variable for each item in the list such as a timer, and I don't want the scrolling to be too slow! How should I update the timers the best way?
Create a member variable for item OnClickListener and set it in Holder's constructor.It will be one listener in your adapter when app is running.
Jerky Scrolling
Since you are using RecyclerView I don't think that you will face any issue with scrolling because RecyclerView inherently comes with ViewHolder Pattern. (In case of Simple listView you have to make ViewHolder to avoid jerky scrolling)
Code improvement
Instead of adding a Listener in ViewHolder, make it a Class variable in your RecyclerView Adapter.
There is a standard way to add a Listener in RecyclerView
Create a listener
interface ClickListener{
void click();
}
implement this listener to Your Activity
YourActivity implements ClickListener{
}
Typecast this listener in Your Adapter
YourAdapter extends RecyclerView.Adapter<YourAdapter.Holder>{
ClickListener listener;
public YourAdapter(Context context)
{
this.context = context;
listener = (ClickListener)context;
}
public class Holder extends RecyclerView.ViewHolder {
TextView firstName;
TextView lastName;
public Holder (final View itemView) {
super(itemView);
firstName = itemView.findViewById(R.id.firstName );
lastName= itemView.findViewById(R.id.lastName);
}
// Item Click listener goes here.
#Override
public void onBindViewHolder(DownLoadViewHolder holder, final int position) {
// Do something
listener.click();
}
}
Just giving you the overview.
You can see THIS for reference.
How can I keep the FloatingActionbutton above the "blue bottom bar" when scrolling down? The bar is the last element of my Fragment so it only needs to move up by a few dp.
Behaviour should be similar to the Snackbar behaviour.
Assuming the BottomBar's ViewHolder is different from the other items in your Recycler view's adapter. You can create an interface that communicates with your FAB whenever the BottomBar's viewholder is bidden in the onBindViewHolder method. If it is, it fires off and some other method checks whether the lastvisible position is equal to the BottomBar's position
For example.
Your Adapter
public class SomeAdapter extends extends RecyclerView.Adapter<SomeAdapter.ViewHolder>{
OnBottomBarBinned onBottomBarBinned;
public interface OnBottomBarBinned{
void binned();
}
public SomeAdapter(OnBottomBarBinned onBottomBarBinned){
this.onBootmBarBinned = onBottomVarBinned;
}
public static class Viewholder extends RecyclerView.Adapter{
ViewHolder(View v){
super(v);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder,int position){
if(viewHolder.item.getViewId()==R.id.yourBottomBarId){
onBottomBarBinned.binned();
}}
}
}
Then when attaching the adapter
yourRecyclerView.setAdapter(new SomeAdapter(new OnBottomBarBinned(){
void binned(){
if(yourLayoutManager.findLastVisiblePosition==bottomBarPosition){
yourFab.setTranslationY(someDp);
}
else{
yourFab.setTranslationY(0);
}
}});
Are you using a FrameLayout/ CoordinatorLayout? This should be easily accomplished if you keep your FAB declared above your bottom bar in XML.
I have implement a RecyclerView and it works fine. I have an ArrayList which contains the data for the recycler view. The layout of each item is complicated. It contains two frameLayout. The framelayout1 contains an image and a text and the framelayout2 contains an image and four texts. When the user clicks on the framelayout1 I want to open the Activity1 and when the users clicks on the framelayout2 I want to open the Activity2. I have already search for the onClick in Recycler View and I have found very useful this. But how can I get the position of the arrayList in order to pass it via Intent in the activity1 or activity2?
Try getAdapterPosition() from inside the view holder so that you may get the adapter position of the click the user made.
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(context, String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
}
}
For more in getAdapterPosition() follow this link
Try this
public class ClosetListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
ClosetListAdapter (CallBack callback){
this.callback = callback
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder baseholder, int position) {
ViewHolder holder = (ViewHolder) baseholder;
holder.setPosition(position);
holder.name.setText(product.getName());
}
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView name = null;
private OnProductClickListener onProductClickListener;
public ViewHolder(View itemView, OnProductClickListener onClickListener) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.item_name);
itemView.setOnClickListener(this)
}
public void setProdcut(Product product) {
this.product = product;
}
#Override
public void onClick(View v) {
if (callback!= null) {
callback.itemClicked(pos);
}
}
public void setPosition(int position){
this.pos = position;
}
}
interface CallBack {
void itemClicked(int position);
}
}
I've also faced the same problem.
I wanted to find of the position of the clicked/selected item of the RecyclerView() and perform some specific operations on that particular item.
getAdapterPosition() method works like a charm for these kind of stuff. I found this method after a day of long research and after trying numerous other methods.
int position = getAdapterPosition();
Toast.makeText(this, "Position is: "+position, Toast.LENGTH_SHORT).show();
You do not have to use any extra method. Just create a global variable named 'position' and initialize it with getAdapterPosition() in any of the major method of the adapter (class or similar).
Here is a brief documentation from this link.
getAdapterPosition
added in version 22.1.0
int getAdapterPosition ()
Returns the Adapter position of the item represented by this ViewHolder.
Note that this might be different than the getLayoutPosition() if there are pending adapter updates but a new layout pass has not happened yet.
RecyclerView does not handle any adapter updates until the next layout traversal. This may create temporary inconsistencies between what user sees on the screen and what adapter contents have. This inconsistency is not important since it will be less than 16ms but it might be a problem if you want to use ViewHolder position to access the adapter. Sometimes, you may need to get the exact adapter position to do some actions in response to user events. In that case, you should use this method which will calculate the Adapter position of the ViewHolder.
Happy to help. Feel free to ask doubts.
I'm trying to implement a way to handle item selection on a RecyclerView. I personally don't like the way suggested in some answers on SO of passing through gestures, and I thought that implementing an OnClickListener, as suggested here and here, was waaay cleaner.
The fact is that... this pattern doesn't actually work! I'm really not able to understand why my OnClickListener.onClick is never called. It's kinda like another method intercepts the click before onClick can take care of it.
This is my code:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView tvName;
ImageView star;
public ViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.CHAT_ITEM_name);
star = (ImageView) itemView.findViewById(R.id.CHAT_ITEM_star);
Fonts.setTypeface(tvName, regular);
}
#Override
public void onClick(View view) {
int position = getLayoutPosition();
select(position);
}
}
Unfortunately it's very important for me to able to access the position of the clicked item in the whole dataset, in order to remove it, so doing something like indexOfChild isn't acceptable too: I tried, but this method gives you the position of the item in the visibile part of the list, thus making list.remove(position) impossible.
Looking at the updated code: you are not setting the onClickListener to any of the views in the ViewHolder. It is an understandable mistake to forget the click listener.
Just use:
tvName.setOnClickListener(this);
star.setOnClickListener(this);
You can set to both or just one of them. You can also simply get the parent layout of these two views, so that the whole item itself in the adapter can be clickable.
itemView.setOnClickListener(this);
You can do it in your onBindViewHolder
#Override
public void onBindViewHolder(ReportViewHolder holder, int position {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// handle your click here.
} });
}
Simplely Click Handler your ViewHolder. Recycler View don't have special attaching click handlers like ListView which has the method setOnItemClickListener().
** public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
** in public ViewHolder(Context context, View itemView) set public void onClick(View view)
** get position by: int position = getLayoutPosition(); User user = users.get(position);
Hi I have a app that uses a Recycler view to display a bunch of items. Now I want to run an android test on the list but I don't know how to set a programmatic click on a given item. Can anyone tell me how to achieve this?
You have to implement it from scratch. The RecyclerView lacks for some of the awesome features that a ListView provides by default. Given this, in the adapter you have to declare an interface for the Observer between Fragment/Activity and the RecyclerView.
The correct method to attach this click event is onBindViewHolder. Then in the adapter you keep the reference to the CustomListener or the View.OnClickListener.
Here is a quick example on how to do this:
#Override
public void onBindViewHolder(SearchListAdapter.ViewHolder holder, final int position) {
//Item clicked
holder.mParent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Select or deselect
mListener.notify(holder, position);
}
});
}
And the ViewHolder should be like:
public class ViewHolder extends RecyclerView.ViewHolder {
private View mParent;
public ViewHolder(View itemView) {
super(itemView);
mParent = itemView;
}
}
Where mParent is the current row View.