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

时间:2016-01-20 18:48:34

标签: android android-recyclerview recycler-adapter

设置我有RecyclerView个自定义适配器和自定义ViewHolder

我理解当onCreateViewHolder()用完ViewHolders以便回收并需要一个新方法时,会调用RecyclerView方法。所以我只是在那里夸大布局并将其传递给新的ViewHolder.

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

我看到的行为当活动首次启动时,所有条目都是正确的。但是,当我添加新条目或删除现有条目时,事情开始变得有趣。

  • title TextView始终设置正确
  • 主要版面的背景颜色看似随意变化,我假设是因为RecyclerView正在重用旧版
  • 我已经实现的自定义视图也是如此,即使我使它失效并传递新的值会显着改变其外观

所以我想知道:一旦视图被重用,为什么onBindViewHolder()中的值没有变化?或者,如果我错了,布局随机切换的真正原因是什么?

TaskListAdapter

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

如果其他任何事情在这里重要,请告诉我。我很乐意相应地更新问题。

1 个答案:

答案 0 :(得分:7)

视图重复使用后,onBindViewHolder确实会更改值。

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

  1. 在将ViewHolder设置为其他值或
  2. 之前,先将onBindViewHolder的所有值重置为默认值
  3. 确保所有内容都设置在RecyclerView内,因此无法判断它之前曾与其他内容绑定过。
  4. 随机背景颜色变化:

    您怀疑随机背景颜色问题是由ViewHolder重复使用 if(!dbNode.isAppointment()) { wrapper.setBackgroundColor(ContextCompat.getColor(wrapper.getContext(), R.color.lightGray)); } 引起的。

    发生这种情况的原因是由于以下代码:

    ViewHolder

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

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

    • 在执行if语句之前将wrapper.setBackgroundColor(/* default background color */); if(!dbNode.isAppointment()) { wrapper.setBackgroundColor(ContextCompat.getColor(wrapper.getContext(), R.color.lightGray)); } 的背景颜色设置为某种默认颜色(根据上述解决方案1):

      ViewHolder
    • 在if语句中添加一个else块,将if(!dbNode.isAppointment()) { wrapper.setBackgroundColor(ContextCompat.getColor(wrapper.getContext(), R.color.lightGray)); } else { wrapper.setBackgroundColor(/* appointment background color */); } 的背景颜色设置为适当的颜色(根据上面提到的解决方案2)

      RecyclerView.Adapter
    • 覆盖dbNode.isAppointment()&#39; s getItemViewType以返回基于var $elem = $('#elem'); $elem.css('max-height', $elem.width() * 0.75 ); 的不同视图类型,并创建不同的ViewHolder子类以显示每个视图类型

    P.S。我不知道自定义视图会出现什么问题......对不起