首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ViewHolder布局更新不适用于onBindViewHolder()

ViewHolder布局更新不适用于onBindViewHolder()
EN

Stack Overflow用户
提问于 2016-01-20 18:48:34
回答 1查看 1.4K关注 0票数 4

我有一个带有自定义适配器和自定义ViewHolderRecyclerView

我知道onCreateViewHolder()方法是在RecyclerView用完ViewHolders来循环时调用的,需要一个新的方法。所以我只是在里面膨胀一个布局,然后把它传递给一个新的ViewHolder.

此外,onBindViewHolder()负责在ViewHolder创建或回收新的ViewHolder后立即将数据填充到RecyclerView中。所以,我在这里要做的是调用我的方法holder.setNode(),将一个数据对象传递给ViewHolder

我看到的行为当活动第一次启动时,所有条目都是正确的。然而,当我添加新条目或删除现有条目时,事情开始变得有点滑稽。

  • 始终正确地设置title TextView
  • 主布局的背景色似乎是随意变化的,我猜想是因为RecyclerView正在重用旧布局
  • 正如我实现的自定义视图一样,尽管我正在使它失效并传递新的值,这些值明显地改变了它的外观。

因此,我想知道:为什么这些值在视图被重用后不会在onBindViewHolder()中立即改变呢?或者如果我错了,随机转换布局的真正原因是什么?

TaskListAdapter

代码语言:javascript
复制
class TaskListAdapter extends RecyclerView.Adapter<TaskListAdapter.TaskViewHolder> {

private ArrayList<NodeHandler.DbNode> dbNodeList = new ArrayList<>();
...

@Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.small_task_view, parent, false);
    return new TaskViewHolder(v);
}

@Override
public void onBindViewHolder(TaskViewHolder holder, int position) {
    final NodeHandler.DbNode dbNode = dbNodeList.get(position);
    holder.setNode(dbNode);
    holder.wrapper.findViewById(R.id.card_details).setVisibility(View.GONE);
}

...

public static class TaskViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
    private FrameLayout wrapper;
    private TextView title;
    private NodeHandler.DbNode dbNode;

    public TaskViewHolder(View view) {
        ...
    }

    public void setTitle(String str) {
        title.setText(str);
    }

    public void setMarkers(@IntRange(from = 1, to = Node.MAX_URGENCY) int urgency, @IntRange(from = 1, to = Node.MAX_IMPORTANCE) int importance) {
        if(!dbNode.isAppointment()) {
            wrapper.setBackgroundColor(ContextCompat.getColor(wrapper.getContext(), R.color.lightGray));
        }
        ((QuadrantView) wrapper.findViewById(R.id.quadrant_view)).setDimensions(importance, urgency);
        // setDimensions will invalidate the view
    }

    public void setNode(NodeHandler.DbNode dbNodeObject) {
        this.dbNode = dbNodeObject;
        setTitle(dbNode.toString());
        setMarkers(dbNode.getUrgency(), dbNode.getImportance());
        setTips();
    }
}
}

如果这里还有什么事请告诉我。我很乐意相应地更新这个问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-20 19:39:11

一旦视图被重用,onBindViewHolder中的值确实会被更改。

看似随机切换布局的真正原因是,onBindViewHolder目前的实现方式假定ViewHolder是新创建的,并且是第一次绑定。相反,onBindViewHolder的实现方式应该假定被绑定的ViewHolder被重用,所以它应该这样做:

  1. 首先将ViewHolder的所有值重置为默认值,然后再将其设置为其他值或
  2. 确保所有东西都是在onBindViewHolder内部设置的,这样就不能确定它以前是绑定到其他东西上的。

随机背景色变化:

您正确地怀疑,随机背景颜色问题是由RecyclerView重用ViewHolders引起的。

之所以会发生这种情况,是因为以下代码:

代码语言:javascript
复制
    if(!dbNode.isAppointment()) {
        wrapper.setBackgroundColor(ContextCompat.getColor(wrapper.getContext(), R.color.lightGray));
    }

它只在ViewHolder不是约会时设置背景。因此,如果被重用的ViewHolder以前不是用于约会,而是当前用于约会,那么它的背景色将是不合适的。

若要解决此问题,请执行以下任何操作:

  • 在执行if语句之前,将ViewHolder的背景色设置为某种默认颜色(如上面提到的解决方案1所示): wrapper.setBackgroundColor(ContextCompat.getColor(wrapper.getContext(),wrapper.setBackgroundColor(/*默认背景色*/);if(!dbNode.isAppointment()) {dbNode.isAppointment R.color.lightGray);}
  • 在if语句中添加一个其他块,将ViewHolder的背景色设置为适当的颜色(如上面提到的解决方案2所示) if(!dbNode.isAppointment()) {dbNode.isAppointment R.color.lightGray);} wrapper.setBackgroundColor(/*约会背景色*/);}
  • 重写RecyclerView.AdaptergetItemViewType以基于dbNode.isAppointment()返回不同的视图类型,并创建用于显示每个视图的不同的ViewHolder子类。

附注:我不知道定制views...sorry会有什么问题

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34908061

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档