How to get adapter position in onCreate of RecyclerView.ViewHolder in Android - java

#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate
(R.layout.tfl_conversation_item, parent, false);
conversations.get(getBindingAdapterPosition(view));
getAbsoluteAdapterPosition() ;
getchildAdapterPosition(view);
return new ConversationAdapter.ViewHolder(view);
}
I used the above code, but didn't succeed. I want to get the adapter position in onCreate of RecyclerView.

You need to use viewType, if you want the value of viewType to be equal to your position, use the following code:
#Override
public int getItemViewType(int position) {
return position;
}
This is the solution, but the work of viewType is something else, learn more.

Related

Android Recycler View with multiple Views [duplicate]

This question already has answers here:
How to create RecyclerView with multiple view types
(23 answers)
Closed 3 years ago.
I am making an app in which I want to put texts , images and videos all in separate ViewHolders (similar to Instagram and Facebook). I know that we have to use a Recycler View with multiple ViewTypes . I am using firebase as my storage . How do I retrieve the items from firebase and place them in the appropriate ViewHolder . Please help me.
public class GovtjobsAdapter extends RecyclerView.Adapter {
private List<GovtjobBean> govtjobList;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView tv_govtjob_title,tv_govtjob_lastdatetoapply,tv_govtjob_location;
public MyViewHolder(View view) {
super(view);
tv_govtjob_title = (TextView) view.findViewById(R.id.tv_govtjobs_title);
tv_govtjob_lastdatetoapply = (TextView) view.findViewById(R.id.tv_govtjob_lastdatetoapply);
tv_govtjob_location = (TextView) view.findViewById(R.id.tv_govtjob_location);
}
}
public GovtjobsAdapter(List<GovtjobBean> govtjobList) {
this.govtjobList = govtjobList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.govtjob_lists, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
GovtjobBean govtjoblist = govtjobList.get(position);
holder.tv_govtjob_title.setText(govtjoblist.getGovt_title());
holder.tv_govtjob_lastdatetoapply.setText(govtjoblist.getGovt_lastdatetoapply());
holder.tv_govtjob_location.setText(govtjoblist.getGovt_location());
}
#Override
public int getItemCount() {
return govtjobList.size();
}
}
You can use the getItemViewType(int position) method of your adapter to do this. In this method, you can check the type of item at the current position if it is an Image, Video or Text and return a specific value for each. Then in your onCreateViewHolder(ViewGroup parent, Int viewType) you can use that viewType parameter to inflate your views.
You will need to create a custom recycler view class where you override onCreateViewHolder(ViewGroup parent, Int viewType).
Here is my example:
(1) in your recyclerview class create custom view holder classes. Example:
class ViewHolderCurrent extends RecyclerView.ViewHolder {
TextView locationTV;
TextView conditionTV;
...
public ViewHolderCurrent(View listItemView) {
super(listItemView);
locationTV = listItemView.findViewById(R.id.location_main_4);
conditionTV = listItemView.findViewById(R.id.condition_main_4);
...
}
}
(2) override the onCreateViewHolder to your custom view holders:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 1:
View viewCurrent = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item4, parent, false);
return new ViewHolderCurrent(viewCurrent);
case 2:
...
case 3:
...
}
return null;
}
(3)Override the onBindViewHolder() to populate the viewholder of your choice. Example:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case 1:
ViewHolderCurrent viewHolderCurrent = (ViewHolderCurrent) holder;
viewHolderCurrent.locationTV.setText(*text*);
viewHolderCurrent.conditionTV.setText(*text*);
break;
case 2:
...
}
}
My full source code is here
You have to use recyclerview ViewTypes, check the example in this link:
Android RecyclerView Example – Multiple ViewTypes
Or you can use library like FastAdapter, it is awesome library that handle adapter items type:
https://github.com/mikepenz/FastAdapter

Changing one ViewHolder item also affects to other items

I have a simple mp3 player based on RecyclerView.
There is an Adapter and ViewHolder for handling tracks in playlist.
public class TracksAdapter extends RecyclerView.Adapter<TracksAdapter.ViewHolder> {
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cell_playlist, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.trackName.setText("Track " + position);
}
#Override
public int getItemCount() {
return tracks.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView trackName;
ViewHolder(View itemView) {
super(itemView);
trackName = itemView.findViewById(R.id.trackName);
}
}
}
When I click on track I want to change background color of selected track in playlist. Problem is when I set background color to one item it's will be affected to every tenth cell in playlist.
For example if there are 100 tracks in the playlist, 10 tracks will be highlighted including the selected.
Method findViewHolderForAdapterPosition(position) returns ViewHolder with selected track.
private void setTrackColor(int position) {
RecyclerView.ViewHolder holder =
recyclerView.findViewHolderForAdapterPosition(position);
if (holder == null) return;
View item = holder.itemView;
item.setBackgroundColor(ContextCompat.getColor(main, R.color.playing));
}
You can't change the color of a view direcly. In a RecyclerView, all the Views are re-used. So, if you change the color in a position, you may indirecly change the color in other positions because same view will be re-used.
You must save the position of the currently playing track separately. This way, during onBindViewHolder, you check if current view being bind is the track currently playing. If it is the same track, apply some color. If it is not the same color, restore default color
public class TracksAdapter extends RecyclerView.Adapter<TracksAdapter.ViewHolder> {
private int mTrackPlaying = -1;
public void setTrackPlaying(int position) {
mTrackPlaying = position;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.trackName.setText("Track " + position);
if(position == mTrackPlaying) {
holder.itemView.setBackgroundColor(ContextCompat.getColor(main, R.color.playing));
} else {
// Here, you must restore the color because the view is reused.. so, you may receive a reused view with wrong colors
holder.itemView.setBackgroundColor(ContextCompat.getColor(main, R.color.NOT_playing));
}
}
}
And then
private void setTrackColor(int position) {
TracksAdapter adapter = (TracksAdapter) recyclerView.getAdapter();
adapter.setTrackPlaying(position);
// Line below will `RecyclerView` to re-draw that position.. in other words, it will triggers a call to `onBindViewHolder`
adapter.notifyItemChanged(position);
// Reset the color of song previously playing..
adapter.notifyItemChanged(oldPosition);
}

Why is holder.textView accessible directly witout creating an object of the class?

I have this adapter class:
public class ItemAdapter extends PagedListAdapter<Item, ItemAdapter.ItemViewHolder> {
private Context context;
ItemAdapter(Context context) {
this.context = context;
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item, parent, false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ItemViewHolder holder, int position) {
Item item = getItem(position);
holder.textView.setText(item.name); //Why?!?!
}
class ItemViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ItemViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.name_text_view);
}
}
}
Inside the onBindViewHolder() method, why can I access directly holder.textView since ItemViewHolder is not static? How is this possible to access a field without creating on object of the class?
Just because you're not creating an instance (what you called "object") doesn't mean you aren't using one. In fact, you did create an instance of ItemViewHolder, right in your onCreateViewHolder() method:
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item, parent, false);
return new ItemViewHolder(view); //right here
}
The instance returned by onCreateViewHolder() is what's passed to onBindViewHolder() (onCreateViewHolder() and onBindViewHolder() are called for each item in your dataset, so there's a unique-ish instance of ItemViewHolder for each item [RecyclerViews actually recycle ViewHolders, but that's another subject]).
ItemViewHolder.textView
wouldn't work because that is an example of static access.
What you're referencing, though, is an actual instance.
TL;DR, holder is an instance. It's not a static reference.

Android Studio Firebase Recyclerview upgrading error

I have to develop a Recyclerview with PopulateViewHolder in an older version of Firebase. Now I'm trying to upgrade the version (not at the last one) and I don't know how to use onBindHolder or anything about this new kind of RecyclerView.
Here is how I had the setup:
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Event, EventViewHolder>(
Event.class,
R.layout.event_row,
EventViewHolder.class,
mDatabase.orderByChild("timeStamp")
) {
#Override
protected void populateViewHolder(final EventViewHolder viewHolder, final Event model, final int position) {
final String id = getRef(position).getKey().toString().trim();
viewHolder.setTitle(model.getTitle());
viewHolder.setDateWords(model.getDateWords());
viewHolder.setDesc(model.getDesc());
}
};
mEventList.setAdapter(firebaseRecyclerAdapter);
}
public static class EventViewHolder extends RecyclerView.ViewHolder {
View mView;
public EventViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
}
And here it's how I'm trying to do now:
Query searchQuery = mDatabase.orderByChild("timeStamp");
options = new FirebaseRecyclerOptions.Builder<Event>()
.setQuery(searchQuery, Event.class)
.build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Event, EventViewHolder>(options) {
#Override
protected void onBindViewHolder(final EventViewHolder viewHolder, int position, Event model) {
final String id = getRef(position).getKey().toString().trim();
viewHolder.setTitle(model.getTitle());
viewHolder.setDateWords(model.getDateWords());
viewHolder.setDesc(model.getDesc());
}
#NonNull
#Override
public EventViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return null;
}
};
firebaseRecyclerAdapter.startListening();
mEventList.setAdapter(firebaseRecyclerAdapter);
The ViewHolder Class is the same.
Here is the error
Actually, I'm asking for tutorial, because I only find those that make the adapter separately, but I wanna have it in the same activity.
In your public EventViewHolder onCreateViewHolder method, instead of returning a view you are returning null. To solve this, please add the following lines of code inside this method:
#NonNull
#Override
public EventViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
return new EventViewHolder(view);
}
In which item_layout is a custom layout for your item. If you want to use instead of this layout a built-in XML layout document that is part of the Android OS, you can use:
android.R.layout.simple_list_item_1

RecyclerView show data from 2 different layouts

I am using the following code in Adapter class to show data in a RecyclerView, but now I would like to show data from some other ArrayList in a same RecyclerView (at some positions like: 1st position and 6th position) using different layout.
That different layout (assume: another_layout.xml) contains 2 TextViews and an Image, also want to implement click on listener for that layout too..
#Override
public PlaylistCardAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate a card layout
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.youtube_video_card, parent, false);
// populate the viewholder
ViewHolder vh = new ViewHolder(v);
return vh;
}
RecyclerView for more than one layout
1. Override getItemViewType(int position) method
e.g I have two layouts layout1 and layout2.I want layout1 at the top and then layout2. So getItemViewType would be something like this
#Override
public int getItemViewType(int position) {
if(position == 0){ //for layout1
return 1;
}else{
return 2; //for layout2
}
}
2. Different viewholder for each layout like this
class ViewHolder_LayoutOne extends RecyclerView.ViewHolder{
TextView name;
//Constructor
}
class ViewHolder_LayoutTwo extends RecyclerView.ViewHolder{
TextView name;
//Constructor
}
3. Inflate different layouts according to the position
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder vh = null;
if(viewType == 1){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_layout_one,parent,false);
vh = new MyViewHolder_LayoutOne(view);
}else if(viewType == 2){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_layout_two,parent,false);
vh = new MyViewHolder_LayoutTwo(view);
}
return vh;
}
4. Bind your views as per the position
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
switch(getItemViewType(position)){
case 1: //for layout 1
((ViewHolder_LayoutOne)holder).name.setText("");
break;
case 2:// for layout 2
((ViewHolder_LayoutTwo)holder).name.setText("");
break;
}
}
5.Now Most important getItemCount() method //return the number of views
#Override
public int getItemCount() {
return toptitles.length + 1;
// as i have only layout at the top and the remaining size equals the length of the array toptitles.So the overall length would be
//number of views of layout1 + number of views of layout2
}
Hope this helps!!!
you can override getItemViewType, and use different ViewHolder for different layout.
You need to override getItemViewType like this :
#Override
public int getItemViewType(int position) {
Add your condition and return viewType(Constant)
}
Now, Check for viewType and retrun viewHolder accordingly.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEWHOLDER1) {
View v = LayoutInflater.from(activity).inflate(R.layout.layout1, parent, false);
return new ViewHolder1(v);
}else if(viewType == VIEWHOLDER2){
View v = LayoutInflater.from(activity).inflate(R.layout.layout2, parent, false);
return new ViewHolder2(v);
}
}
Now, Check for instance of viewHolder
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ViewHolder1) {
Show values in UI accordingly.
}else if(holder instanceof ViewHolder2){
Show values in UI accordingly.
}
}
You can set the type you want in getItemViewType(int position) with the layout you want. And onCreateViewHolder you can check viewType and inflate the row accordingly.
here is an example.

Categories

Resources