Android RecyclerView如何更改第一个项目的文本颜色

3

我正在使用 AdapterRecyclerView,尝试更改我的 RecyclerView 中的第一个项目的颜色。我在 onBindViewHolder 中进行操作,第一个确实按照我的要求更改了,但如果我检查8个视图,我会看到那一个也被改变了。这有点一致,项目0已更改,1、2、3、4未更改,5已更改,6、7、8、9未更改,10已更改等等......

如果我进行调试,我会看到我的if语句被触发了很多次。如果我在互联网上搜索,我会看到人们使用相同的方式(在 onBindViewHolder 中)。不知道我做错了什么 :(

@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);
        }
    }

我希望只有第一个项目(适配器位置为0或位置为0)的颜色和背景被更改。现在,其他视图也发生了一致的变化。


6
伪代码:if (position == 0) { change color to 0xFF1D3587 } else { change color to default color }RECYCLERview 的工作方式是回收你的视图。如果你改变了第一个视图的UI,比如背景颜色,那么具有相同背景颜色的视图可能会稍后重新出现。 - Zun
非常感谢Zun,这个方法很有效!但我认为这不是最好的答案。因为else语句会被多次调用,并且每次都会将颜色和背景设置为不同的颜色,这可能会导致性能问题,特别是如果你改变的不仅仅是文本颜色。我希望它只触发一次,然后就完成了。 - Allart
这就是Recycler View的工作原理。它们应该被“回收利用”,也就是重新使用,开发人员需要定义/刷新每个项目的视图属性。话虽如此 - 还有另一种方法 - 请参见我下面的答案。 - Vinay W
你描述的是ListView的工作原理。如果你设置了一次,视图将保持不变。RecyclerView将对每个视图进行回收利用。此外,设置多个背景颜色不会影响性能。你可以自己测试! - Zun
@Zun 我理解你的意思(我想应该是xD),你觉得我发布的答案怎么样? - Allart
如果你想要一个诚实的意见,那么我会说它很糟糕。你没有正确地使用RecyclerView。你还不如使用ListViews。 - Zun
5个回答

2
我认为这样做对性能更好。每次创建/回收时,它只会触发第一个项目。"Original Answer" 的意思是 "最初的回答"。
private static final int TYPE_AVAILABILITY = 1;
private static final int TYPE_WEEK = 2;

我之前在一个项目中使用过这种方式。"Original Answer"翻译成"最初的回答"。
@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;
    }
}

2

导致这种奇怪行为的代码行是:

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

每当您必须在recyclerView的onBindViewHolder方法中添加if条件时,请勿仅使用它。也要与else部分一起使用。

如果您正在 if 部分进行UI或数据更新,则请在代码的 else 部分将其恢复为正常状态。

Original Answer翻译成"最初的回答"

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

如果您使用if (...) else if (...),这也会导致问题,因为UI会困惑当没有一个条件匹配时我该做什么。因此,始终将else ()括号作为默认行为。即if (...) else if (...) else ()
注意:这适用于所有条件公式,如switcheswhen等。

1
尝试在类oSchedule中添加一个标志:

Try
保留HTML,不要解释。

private boolean isFirstItem;

在构建数据 oScheduleArrayList 时,设置第一个项 oSchedule.isFirstItem = true;
在适配器中:

@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);
    }
}

当您需要修改列表并在活动中刷新回收视图时:
for (int i = 0; i < oScheduleArrayList.size(); i++) {
    oScheduleArrayList.get(i).setIsFirstItem(i == 0);
}
adapter.notifyDataSetChanged();

嗯,当使用recyclerview时,我习惯于在adapter之外修改UI的模型,因为这样更易于管理。但是,如果您只需要设置一个单元格的UI,则使用Vinay的方法会更好。


那么你在哪里将isFirstItem设置为true?是在onBind中的if(position == 0)中吗? - Allart
@Allart 不是,在构建oScheduleArrayList时设置。就像在适配器外的activity/fragment中一样。 - TylerQITX
好的,我按照你说的做了,它可以运行了,但是我仍然有一个问题:列表项号码0被着色了,1、2、3、4没有,5是6、7、8、9也没有,10以后的也没有。 - Allart

0
其他视图看起来像第一个项目的原因是,当第一个项目被“回收”作为第8个项目时,它保留了第一个项目的视图属性,除非在绘制之前更改它们。您可以像这样做来解决它:
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);

    }

另一种解决方案是对第一个项目和其余项目使用不同的ItemType。 使用这种技术,您可以创建不同的视图持有者(在您的情况下为两个),并且回收站视图将仅针对给定项目类型的相应(非第一个项目,在您的情况下)进行回收。


是的,我在评论中看到了这个答案,请阅读我的评论和他的评论:P - Allart
是的,我之前看过那个解决方案,也用过它。但由于我只在两个视图中更改了一个东西,所以我认为这对于仅仅那些东西来说有点太多的代码 :P 我喜欢尽可能地优化。 - Allart

0

这是因为当您滚动时,适配器再次使用相同的itemView,并且在该项处于位置0时更改了颜色,但在适配器再次使用它时没有将其恢复为默认颜色,所以您需要做的是

@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);
    }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接