Android RecyclerView how to change first item it's text color

Viewed 2508

I'm using a Adapter and RecyclerView. I try to change the color of the first item in my RecyclerView. I do this in my onBindViewHolder and the first one indeed changes how i want it to but if i check 8 views furter i see that that one is changed aswell. It's a bit consistant, item number 0 is changed, 1,2,3,4 isn't 5 is, 6,7,8,9 isn't 10 is etc...

If I go debugging i see that my if statement is getting triggerd alot of time's. If i search on internet I see people use the same kinda way (in onBindViewHolder). Dont know what im doing wrong :(

@Override
public void onBindViewHolder(@NonNull oScheduleAvailabilityViewHolder scheduleAvailabilityViewHolder, int position) {
    oSchedule oSchedule = oScheduleArrayList.get(position);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTypeface((oSchedule.getSelected()) ? Typeface.DEFAULT_BOLD : Typeface.SANS_SERIF);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setText(oSchedule.getScheduleName());

    if (position == 0) {
            scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
            scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);
        }
    }

I want only the first item (adapterPosition 0 or position 0) to be changed in color and background. Right now also a consistant amount of other views are.

5 Answers

I think this way it work's better for performance. It will trigger only the first item each time created/recycled.

private static final int TYPE_AVAILABILITY = 1;
private static final int TYPE_WEEK = 2;

I used this way once before in a project.

@Override
public void onBindViewHolder(@NonNull oScheduleAvailabilityViewHolder scheduleAvailabilityViewHolder, int position) {
    oSchedule oSchedule = oScheduleArrayList.get(position);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTypeface((oSchedule.getSelected()) ? Typeface.DEFAULT_BOLD : Typeface.SANS_SERIF);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setText(oSchedule.getScheduleName());

    if (scheduleAvailabilityViewHolder.getItemViewType() == TYPE_AVAILABILITY) {
        Log.i(TAG, "onBindViewHolder: TEST FIRST");
        scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
        scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);
    }
}
@Override
public int getItemViewType(int position) {
    if (position == 0) {
        return TYPE_AVAILABILITY;
    } else {
        return TYPE_WEEK;
    }
}

Line which cause this weird behaviour,

if (position == 0) {
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
    scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);
}

Whenever you have to add if condition in recyclerView's onBindViewHolder method. Never use it alone. Use it with else part also.

If you are making UI or data update in if part then revert it back to normal in else part of code.

if (position == 0) {
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
    scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);
} else {
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor({DEFAULT_COLOR});
    scheduleAvailabilityViewHolder.test.setBackgroundColor({DEFAULT_COLOR});
}

If you are using if (...) else if (...), this will also create the issue, because UI will confused what I have to do when none of the condition matched. So always use else () bracket as default behaviour. i.e., if (...) else if (...) else ().

Note: This is applied to all the conditional formulas like switches, when and etc.

Try
In class oSchedule, add a flag:

private boolean isFirstItem;

When construct data oScheduleArrayList, set first item oSchedule.isFirstItem = true;
In adapter:

@Override
public void onBindViewHolder(@NonNull oScheduleAvailabilityViewHolder scheduleAvailabilityViewHolder, int position) {
    oSchedule oSchedule = oScheduleArrayList.get(position);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTypeface((oSchedule.getSelected()) ? Typeface.DEFAULT_BOLD : Typeface.SANS_SERIF);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setText(oSchedule.getScheduleName());

    if (oSchedule.isFirstItem) {
        scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
        scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);
    }
}

When you need to modify your list and refresh recycler view in your activity:

for (int i = 0; i < oScheduleArrayList.size(); i++) {
    oScheduleArrayList.get(i).setIsFirstItem(i == 0);
}
adapter.notifyDataSetChanged();

Well, I am used to modify model for UI when using recyclerview, as it is manageable outside adapter. But if you just need to set 1 cell's UI, it would be much better using Vinay's method.

The reason other views appear like the first item is because when the first item is 'recycled' as the, say, 8th item - it retains the view properties of the first item, unless you change them before its drawn.. You can do something like this to fix it

public void onBindViewHolder(@NonNull oScheduleAvailabilityViewHolder scheduleAvailabilityViewHolder, int position) {
    oSchedule oSchedule = oScheduleArrayList.get(position);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTypeface((oSchedule.getSelected()) ? Typeface.DEFAULT_BOLD : Typeface.SANS_SERIF);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setText(oSchedule.getScheduleName());

    if (position == 0) {
            scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
            scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);

    }else{
            scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(DEFAULT_COLOR_HERE);
            scheduleAvailabilityViewHolder.test.setBackgroundColor(DEFAULT_COLOR_HERE);

    }

Another solution is to use a different ItemType for the first item and the rest of the items. Using this technique, you can create different view holders (two, in your case) and the recycler view will only recycle the respective (non-first items, in your case) for a given item type.

It's happening because the adapter is using the same itemView again when your scrolling, and you change the color when the item was in position 0 and never changed it back to default color when the adapter is using it again, so what you have to do is

@Override
public void onBindViewHolder(@NonNull oScheduleAvailabilityViewHolder scheduleAvailabilityViewHolder, int position) {
    oSchedule oSchedule = oScheduleArrayList.get(position);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTypeface((oSchedule.getSelected()) ? Typeface.DEFAULT_BOLD : Typeface.SANS_SERIF);
    scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setText(oSchedule.getScheduleName());

    if (position == 0) {
            scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(0xFFd45155);
            scheduleAvailabilityViewHolder.test.setBackgroundColor(0xFF1D3587);
        }else{
           //retutrn to deaftlt color
             scheduleAvailabilityViewHolder.scheduleAvailabilityTextView.setTextColor(your deafult color);
             scheduleAvailabilityViewHolder.test.setBackgroundColor(your deafult color);
    }
    }
Related