I need to set background color inside onCreateViewHolder.
So, when my position is equal toposition % 2 == 0 then set a background Color, else to set another Color.
My background color is standard from all of my rows, that's why i thought to use it inside onCreateViewHolder and not onBindViewHolder. Correct me if i am wrong. The problem is that when i am using holder.getAdapterPosition inside onCreateViewHolder it returns '-1'. It seems normal to me. But how can i fix that?
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
ViewHolder holder= new ViewHolder(mView);
if(holder.getAdapterPosition % 2 ==0)
{
//Row BackgroundColor to red.
}
else
{
//Row BackgroundColor to Green.
}
return holder;
}
So when i use the code above i am getting exception that it is index out of bound.
Is there any way to fix ?
Try this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(position % 2 ==0) {
holder.itemView.setBackgroundColor(
ContextCompat.getColor(holder.itemView.getContext(), R.color.color_red));
} else {
holder.itemView.setBackgroundColor(
ContextCompat.getColor(holder.itemView.getContext(), R.color.color_green));
}
}
According to ideal solution you should write this code in onBindViewHolder to use "getAdapterPosition".
if you want only different background Color of row in onCreateViewHolder than you can try this,This will give you one red color row and one other color row continuously.
you need to create a global variable.
boolean Manual_color = true;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
ViewHolder holder= new ViewHolder(mView);
if(Manual_color)
{
//Row BackgroundColor to red.
Manual_color = false;
}
else
{
//Row BackgroundColor to Green.
Manual_color = true;
}
return holder;
}
You can set color to the view that you have inflated.
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
ViewHolder holder= new ViewHolder(mView);
if(holder.getAdapterPosition % 2 ==0) {
mView .setBackgroundColor(ContextCompat.getColor(this, R.color.color_red));
} else {
mView.setBackgroundColor(ContextCompat.getColor(this, R.color.color_green));
}
Related
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);
}
Can anyone please please help me
I want to create a recycler view with 1st row scrolling horizontally and the rest should be scrolling vertically just like instagram home page.
I have looked up almost everything but no luck.
Please can anyone help.
In your adapter class
private static final int POSTER = 1; //for sliding item
private static final int CHILDGROUP = 2; //normal items
In getItemViewType()
#Override
public int getItemViewType(int position) {
if (position == 0 )
return POSTER;
else
return CHILDGROUP;
}
In onCreateViewHolder() check which item & inflate layout as per item
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == POSTER) {
View view = LayoutInflater.from(mContext).inflate(R.layout.listrow_auto_viewpager, parent, false);
return new PosterSliderHolder(view);
} else {
View view = LayoutInflater.from(mContext).inflate(R.layout.listrow_sub_category, parent, false);
return new GroupViewHolder(view);
}
}
In onBindViewHolder() check the item type & load the data
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == POSTER) {
final PosterSliderHolder posterViewHolder = (PosterSliderHolder) holder;
//your logic for sliding item (horizontal recyclerview )
}
else{
final GroupViewHolder groupViewHolder = (GroupViewHolder) holder;
//normal list item
}
}
This is my code for RecyclerView:
public RecyclerGameAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = null;
if (viewType == AD_VIEW_TYPE) {}
else{
v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.recyclerview_games, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
I don't know how to declare the part that I´m showing the AdView in RecyclerAdapter.
Can you help me?
You would like to check the item type of the RecyclerView and then act accordingly. Use, the #Override method,
#Override
public int getItemViewType(int position)
{
if (position % 5 == 0){
return AD_TYPE;
}else{
return CONTENT_TYPE;
}
}
Then you can bind the content or the Ad to the item in onCreateViewHolder.
View view = null;
if (viewType == AD_TYPE)
{
view = new AdView(activity, AdSize.BANNER, ADMOB_ID);
float density = activity.getResources().getDisplayMetrics().density;
int height = Math.round(AdSize.BANNER.getHeight() * density);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.FILL_PARENT,height);
view.setLayoutParams(params);
view.loadAd(new AdRequest());
}
else{
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_layout, viewGroup, false);
}
RecyclerView.ViewHolder viewHolder = new RecyclerView.ViewHolder(view);
return viewHolder;
This should do the job.
Also check out, this thread and this thread for more inputs. Similar questions as yours. The second one is exactly a copy of yours. Found it after answering your question.
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.
I'm attempting to create a Gridview of icons with the Imageview set to one of two images like in my example below:
I'm retrieving two values from the sqlite content provider, one for the number of stamps and the other for the max number of stamps.
I use a custom adapter with a view holder pattern so I attempt to set the model onLoadFinished() in the Fragment. The model I've currently tried is an int[] with either value of 0 or 1 in the values to determine if green stamp is used or gray. This isn't working however as nothing is being displayed in the GridView.
Here's the code snippet from onLoadFinished() from the Fragment:
imageSourceModel = new int[data.getInt(data.getColumnIndex(RewardsEntry.COLUMN_REW_MAX_POINTS))];
int i = data.getInt(data.getColumnIndex(RewardsEntry.COLUMN_REW_POINTS));
for (int j = 0; j < imageSourceModel.length; j++, i--) {
if (i > 0) {
imageSourceModel[j] = 1;
} else {
imageSourceModel[j] = 0;
}
}
stampGridAdapter.setModel(imageSourceModel);
and the code from the custom Adapter:
#Override
public View getView(int i, View view, ViewGroup parent) {
ViewHolder viewHolder;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_item_discover, parent, false);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
if (model[i] > 0) {
viewHolder.stampView.setImageResource(R.drawable.ic_approved_stamp);
} else {
viewHolder.stampView.setImageResource(R.drawable.ic_approved_stamp_disabled);
}
return view;
}
And simple ViewHolder:
private class ViewHolder {
public ImageView stampView;
public ViewHolder(View view) {
stampView = (ImageView) view.findViewById(R.id.grid_stamp_image);
}
}
If I had to guess, I would say that it fails because of the creation order such that getView() is completed before onLoadFinished() can pass the model in. I'm just not sure how to work around this or what other methods I could use. Any help is appreciated.
For what you want to achieve, this seems unnecessary complicated to me, especially the double variable loop. To cut it simple I'd just do this:
in onLoadFinished()
int maxPoints = data.getInt(data.getColumnIndex(RewardsEntry.COLUMN_REW_MAX_POINTS));
int currentPoints = data.getInt(data.getColumnIndex(RewardsEntry.COLUMN_REW_POINTS));
mGridView.setAdapter(new RewardPointAdapter(getActivity(), currentPoints, maxPoints);
your adapter could look like this:
public class RewardPointAdapter extends BaseAdapter {
private LayoutInflater mLayoutInflater;
private int mMaxRewardPoints;
private int mCurrentRewardPoints;
public RewardPointAdapter(Context context, int currentRewardPoints, int maxRewardPoints) {
mLayoutInflater = LayoutInflater.from(context);
mMaxRewardPoints = maxRewardPoints;
mCurrentRewardPoints = currentRewardPoints;
}
#Override
public int getCount() {
return mMaxRewardPoints;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.list_item_discover, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (position < mCurrentRewardPoints) {
viewHolder.stampView.setImageResource(R.drawable.ic_approved_stamp);
} else {
viewHolder.stampView.setImageResource(R.drawable.ic_approved_stamp_disabled);
}
return convertView;
}
private class ViewHolder {
public ImageView stampView;
public ViewHolder(View view) {
stampView = (ImageView) view.findViewById(R.id.grid_stamp_image);
}
}
}