如何在图片路径为空时隐藏RecyclerView条目?
解决RecyclerView设置条目GONE后仍占位的问题
我明白你遇到的困扰——直接设置View.GONE或者修改LayoutParams高度都没生效,还不能提前过滤列表。这其实是RecyclerView的ViewHolder复用机制和布局测量逻辑在搞鬼,下面给你两个靠谱的解决方案:
方案一:在绑定ViewHolder时完整重置布局参数(适配复用场景)
问题的核心是ViewHolder会被复用,你只在空路径时设置GONE和0高度,但没在非空路径时恢复原布局状态,导致复用的ViewHolder保持了之前的隐藏状态。另外,必须明确修改RecyclerView.LayoutParams才能彻底消除占位:
@Override public void onBindViewHolder(StudioAdapter.StudioViewHolder vh, int position) { final String path = StudioLogoPaths.get(position); // 强转成RecyclerView专用的布局参数 RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) vh.itemView.getLayoutParams(); if (path.isEmpty()) { vh.itemView.setVisibility(View.GONE); // 彻底消除占位:宽高设为0,清空margin layoutParams.height = 0; layoutParams.width = 0; layoutParams.setMargins(0, 0, 0, 0); vh.itemView.setLayoutParams(layoutParams); } else { vh.itemView.setVisibility(View.VISIBLE); // 恢复原布局参数(和你的item布局宽高一致) layoutParams.height = dpToPx(vh.itemView.getContext(), 55); layoutParams.width = dpToPx(vh.itemView.getContext(), 55); // 如果你的item原本有margin,记得这里也要恢复(示例为4dp) int margin = dpToPx(vh.itemView.getContext(), 4); layoutParams.setMargins(margin, margin, margin, margin); vh.itemView.setLayoutParams(layoutParams); Glide.with(vh.itemView.getContext()).load(path).into(vh.logoImage); } } // 辅助工具方法:dp转px private int dpToPx(Context context, int dp) { return (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics() ); }
方案二:用ViewType区分显示/隐藏条目(更优雅的长期方案)
把空路径和非空路径的条目视为两种不同的ViewType,让RecyclerView为它们创建独立的ViewHolder,从根源避免复用带来的状态混乱:
- 先定义两种ViewType:
private static final int VIEW_TYPE_SHOW_LOGO = 0; private static final int VIEW_TYPE_EMPTY = 1;
- 重写
getItemViewType方法:
@Override public int getItemViewType(int position) { return StudioLogoPaths.get(position).isEmpty() ? VIEW_TYPE_EMPTY : VIEW_TYPE_SHOW_LOGO; }
- 在
onCreateViewHolder中创建对应类型的ViewHolder:
@Override public StudioViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_EMPTY) { // 创建一个完全空的View,宽高设为0,直接返回 View emptyView = new View(parent.getContext()); RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(0, 0); emptyView.setLayoutParams(params); return new StudioViewHolder(emptyView); } else { // 加载你原来的item布局 View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_studio_logo_item, parent, false); return new StudioViewHolder(itemView); } }
- 最后在
onBindViewHolder中只处理需要显示的条目:
@Override public void onBindViewHolder(StudioAdapter.StudioViewHolder vh, int position) { if (getItemViewType(position) == VIEW_TYPE_SHOW_LOGO) { String path = StudioLogoPaths.get(position); Glide.with(vh.itemView.getContext()).load(path).into(vh.logoImage); } }
为什么你之前的方法没用?
- ViewHolder复用:滚动时,之前被设为GONE的ViewHolder会被复用给其他位置的条目,如果你没在非空分支恢复布局状态,就会导致正常条目也被隐藏。
- 布局测量逻辑:单纯设置
View.GONE时,部分布局容器(比如你的FrameLayout)在RecyclerView的测量流程中可能仍会保留原空间,必须明确修改RecyclerView.LayoutParams的宽高才能彻底消除占位。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

