如何处理 RecyclerView 中的可扩展 ViewHolder?
How to handle expandable ViewHolders in a RecyclerView?
我的应用程序中有一个 RecyclerView
与 FirestoreRecyclerAdapter
一起工作。 ViewHolders
实现了一个可扩展的 'quick actions' 菜单,该菜单在点击项目时展开,理想的行为是一次只展开一个项目。展开一个项目应该折叠适配器中的所有其他项目。
当屏幕上没有足够的项目来容纳所有项目时,此方法可以正常工作。但是,如果列表延伸到屏幕外,当我尝试遍历适配器的项目时,当分离的或屏幕外的 ViewHolder 尝试调用 getParent()
.
时,我会抛出 NullPointerException
如何迭代适配器中的所有 ViewHolder,或者仅迭代可见的?
相关适配器代码:
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder,
int position, @NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
for (int i = 0; i < mAdapter.getItemCount(); i++) {
if (i != position) {
// ERROR THROWN HERE
BrewViewHolder vh = ((BrewViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(i)));
vh.expanded = false;
}
}
holder.expanded = !holder.expanded;
notifyItemChanged(position);
});
}
相关ViewHolder代码:
public class BrewViewHolder extends RecyclerView.ViewHolder {
// Expanded state
public boolean expanded = false;
...
public BrewViewHolder(@NonNull final View itemView) {
super(itemView);
...
// Set visibility of quick actions based on expanded state
quickActions.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
}
提前致谢!
编辑:作为Gilberto pointed out, this is very expensive. Went with a version of Andrew的解决方案:
private int expandedItemIndex = -1;
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder, int position,
@NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
if (position == expandedItemIndex) {
holder.expanded = false;
expandedItemIndex = -1;
} else {
holder.expanded = true;
if (expandedItemIndex != -1) {
BrewViewHolder otherHolder = ((BrewViewHolder) recyclerView.getChildViewHolder(
recyclerView.getChildAt(expandedItemIndex)));
otherHolder.expanded = false;
}
expandedItemIndex = position;
}
notifyItemRangeChanged(0, recyclerView.getChildCount());
});
}
If(vh!=null){ vh.expanded(false);}
或
使用 try, catch)))
您不应迭代所有视图。您只需要保存展开视图的索引并调用 notifyDataSetChanged
或 notifyItemChanged
.
private int expandedItemIndex = -1;
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder,
final int position, @NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
if (position == expandedItemIndex) {
notifyItemChanged(position);
expandedItemIndex = -1;
} else {
if (expandedItemIndex != -1) {
notifyItemChanged(expandedItemIndex);
}
expandedItemIndex = position;
notifyItemChanged(position);
}
});
if (position == expandedItemIndex) {
// Expand
holder.quickActions.setVisibility(View.VISIBLE);
} else {
// Collapse
holder.quickActions.setVisibility(View.GONE);
}
}
通过迭代 i < recyclerView.getChildCount()
并确保清理 onViewRecycled(ViewHolder holder)
中的 VH 解决:
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder, int position, @NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
for (int i = 0; i < recyclerView.getChildCount(); i++) {
if (i != position) {
BrewViewHolder otherHolder = ((BrewViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(i)));
otherHolder.expanded = false;
}
}
holder.expanded = !holder.expanded;
notifyItemRangeChanged(0, recyclerView.getChildCount());
});
}
@Override
public void onViewRecycled(@NonNull BrewViewHolder holder) {
super.onViewRecycled(holder);
holder.expanded = false;
}
我的应用程序中有一个 RecyclerView
与 FirestoreRecyclerAdapter
一起工作。 ViewHolders
实现了一个可扩展的 'quick actions' 菜单,该菜单在点击项目时展开,理想的行为是一次只展开一个项目。展开一个项目应该折叠适配器中的所有其他项目。
当屏幕上没有足够的项目来容纳所有项目时,此方法可以正常工作。但是,如果列表延伸到屏幕外,当我尝试遍历适配器的项目时,当分离的或屏幕外的 ViewHolder 尝试调用 getParent()
.
NullPointerException
如何迭代适配器中的所有 ViewHolder,或者仅迭代可见的?
相关适配器代码:
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder,
int position, @NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
for (int i = 0; i < mAdapter.getItemCount(); i++) {
if (i != position) {
// ERROR THROWN HERE
BrewViewHolder vh = ((BrewViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(i)));
vh.expanded = false;
}
}
holder.expanded = !holder.expanded;
notifyItemChanged(position);
});
}
相关ViewHolder代码:
public class BrewViewHolder extends RecyclerView.ViewHolder {
// Expanded state
public boolean expanded = false;
...
public BrewViewHolder(@NonNull final View itemView) {
super(itemView);
...
// Set visibility of quick actions based on expanded state
quickActions.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
}
提前致谢!
编辑:作为Gilberto pointed out, this is very expensive. Went with a version of Andrew的解决方案:
private int expandedItemIndex = -1;
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder, int position,
@NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
if (position == expandedItemIndex) {
holder.expanded = false;
expandedItemIndex = -1;
} else {
holder.expanded = true;
if (expandedItemIndex != -1) {
BrewViewHolder otherHolder = ((BrewViewHolder) recyclerView.getChildViewHolder(
recyclerView.getChildAt(expandedItemIndex)));
otherHolder.expanded = false;
}
expandedItemIndex = position;
}
notifyItemRangeChanged(0, recyclerView.getChildCount());
});
}
If(vh!=null){ vh.expanded(false);}
或
使用 try, catch)))
您不应迭代所有视图。您只需要保存展开视图的索引并调用 notifyDataSetChanged
或 notifyItemChanged
.
private int expandedItemIndex = -1;
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder,
final int position, @NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
if (position == expandedItemIndex) {
notifyItemChanged(position);
expandedItemIndex = -1;
} else {
if (expandedItemIndex != -1) {
notifyItemChanged(expandedItemIndex);
}
expandedItemIndex = position;
notifyItemChanged(position);
}
});
if (position == expandedItemIndex) {
// Expand
holder.quickActions.setVisibility(View.VISIBLE);
} else {
// Collapse
holder.quickActions.setVisibility(View.GONE);
}
}
通过迭代 i < recyclerView.getChildCount()
并确保清理 onViewRecycled(ViewHolder holder)
中的 VH 解决:
@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder, int position, @NonNull Brew brew) {
// Bind Views
holder.bind(brew);
// Set expander ClickListener
holder.card.setOnClickListener(v -> {
for (int i = 0; i < recyclerView.getChildCount(); i++) {
if (i != position) {
BrewViewHolder otherHolder = ((BrewViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(i)));
otherHolder.expanded = false;
}
}
holder.expanded = !holder.expanded;
notifyItemRangeChanged(0, recyclerView.getChildCount());
});
}
@Override
public void onViewRecycled(@NonNull BrewViewHolder holder) {
super.onViewRecycled(holder);
holder.expanded = false;
}