【问题标题】:Hiding views in RecyclerView在 RecyclerView 中隐藏视图
【发布时间】:2017-02-28 06:57:55
【问题描述】:

我有这样的代码

public static class MyViewHolder extends RecyclerView.ViewHolder {
    @InjectView(R.id.text)
    TextView label;

    public MyViewHolder(View itemView) {
        super(itemView);
        ButterKnife.inject(this, itemView);
    }

    public void hide(boolean hide) {
        label.setVisibility(hide ? View.GONE : View.VISIBLE);
    }
}

映射到RecyclerView 中的单行。 R.id.text 实际上是布局的根视图,它被膨胀并传递给这里的构造函数。

我正在使用LinearLayoutManager 的默认实现。

在bindViewHolder 中,我在MyViewHolder 的一个实例上调用hide(true),但不是按预期折叠行,而是行变得不可见,保持其在RecyclerView 中的高度和位置。有没有其他人遇到过这个问题?

如何在 RecyclerView 中隐藏项目?

【问题讨论】:

标签: android


【解决方案1】:

没有内置的方法可以在 RV 中隐藏孩子,但当然如果它的高度变为 0,它将不可见:)。我假设你的根布局确实有一些最小高度(或精确高度),即使它已经消失了,它仍然占用空间。

另外,如果你想移除一个视图,把它从适配器中移除,不要隐藏它。您是否有理由要隐藏而不是删除?

【讨论】:

  • 不,我实际上尝试将某些行的高度设置为 0。 LayoutManager 不考虑行高变化。不过你是对的,解决方案是从适配器中“删除”有问题的对象。看我的回答。
  • LayoutManager 确实尊重项目高度。我想知道你是如何改变它们的。我假设您正在调用 view.setLayoutParams 这将触发 LayoutManager 中的重新布局,并且它将获得新的大小。那里应该有其他问题
  • 哦,你是对的,我刚刚意识到我设置的高度不正确。我会把你的答案标记为正确的。
  • 请注意,如果您使用装饰器(例如,在物品之间添加分隔线),您的“隐形”物品仍将被装饰。
  • @yigit 我的情况有一个原因,我将前两项作为常量项。因此,它们始终是列表中的第 1 项和第 2 项。列表中的第一项是控制器,第二项是“添加卡”。当我按下控制器中的按钮时,会出现“添加卡”。该项目的其余部分是模型列表的标准表示。我正在尝试模拟 Facebook 中的发布功能,在该功能中,您始终在列表顶部放置“发布您的想法”卡片,因此我想我可以通过 RecyclerView 制作复合视图。但也许这只是错误的做法
【解决方案2】:

将方法setVisibility(boolean isVisible) 放入ViewHolder。

您可以将itemView 参数(宽度和高度)更改为LayoutManager:

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    ...

    public void setVisibility(boolean isVisible){
        RecyclerView.LayoutParams param = (RecyclerView.LayoutParams)itemView.getLayoutParams();
        if (isVisible){
            param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
            param.width = LinearLayout.LayoutParams.MATCH_PARENT;
            itemView.setVisibility(View.VISIBLE);
        }else{
            itemView.setVisibility(View.GONE);
            param.height = 0;
            param.width = 0;
        }
        itemView.setLayoutParams(param);
    }

    public ViewHolder(View itemView) {
        super(itemView);
        ...
    }
}

并更改 ItemDecoration(分隔线)的可见性:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    ...

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        ...

        for (int i = 0; i < parent.getChildCount(); i++) {

            if (parent.getChildAt(i).getVisibility() == View.GONE) 
                continue;

            /* draw dividers */    

        }
    }
}

【讨论】:

  • 虽然这有效,但它会导致大量的回收测量并使滚动非常卡顿。
  • @MLProgrammer-CiM 但是如果列表中有很多隐藏项,则应该考虑使用其他一些算法来显示它们。例如更改布局管理器。
  • 我们需要弄乱 LayoutParams,View.GONE 不就行了吗?
【解决方案3】:

你可以做到的!

首先,您需要检测要隐藏的项目的哪个位置。您可以自定义 getItemViewType 来做到这一点。

接下来,在 onCreateViewHolder 上,取决于视图类型。你可以这样做:

if(viewType == TYPE_HIDE) {
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.empty_item, parent, false);
                vHolder = new ViewHolder(context, v, viewType, this);
                break;
        }
        return vHolder; 

-> empty item 是一个什么都没有的布局,(换句话说,无论何时创建它都是默认布局)。或代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>

希望对您有所帮助!

【讨论】:

  • 我认为将layout_height设置为0dp或wrap_content是个好主意,如果设置为match_parent,那么每个空单元格将占用父视图...
【解决方案4】:

好的,所以我最终的做法是我拥有整个数据集,例如 myObjects,并且我有一些场景我只想显示该数据集的子集。

由于在RecyclerView 中设置行的可见性不会导致高度崩溃,并且设置行的高度似乎也没有任何作用,我要做的就是保留一个名为 @987654323 的辅助数据集@ 只不过是一个 List&lt;Integer&gt; ,它将索引到 myObjects 以确定将显示哪些对象。

然后我会间歇性地更新 myObjectsShown 以包含正确的索引。

因此,

public int getItemCount() {
    return myObjectsShown.size();
}

和

public void onBindViewHolder(MyViewHolder holder, int position) {
    Object myObject = myObjects.get(myObjectsShown.get(position));
    // bind object to viewholder here...
} 

【讨论】:

  • 这非常聪明和简单。这应该是最好的答案,因为您真的不必干涉getItemViewType 或其他任何事情。但它可以动态隐藏您不想显示的孩子,并且还可以很好地考虑高度变化。
  • 非常聪明的答案
【解决方案5】:

为了在 RecyclerView 中隐藏视图,我在 OnBindViewHolder 中隐藏/显示视图:

if (item.isShown) {
    vh.FooterLayout.setVisibility(View.Visible);
} else {
    vh.FooterLayout.setVisibility(View.Gone);
}

例如 - 从活动中我只是重绘需要的项目: _postListAdapter.notifyItemChanged(position)// 如果你想显示/隐藏页脚 - 位置是 amountOfPosts.size() 并更改布尔变量 - amountOfPosts[amountOfPosts.size()].isShown

【讨论】:

    【解决方案6】:

    为了完整起见,您应该注意将视图可见性设置为 GONE 不会隐藏边距。你需要做这样的事情:

           if(itemView.getVisibility() != GONE) itemView.setVisibility(GONE);
           RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams();
           layoutParams.setMargins(0, 0, 0, 0);
           itemView.setLayoutParams(layoutParams);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-09
      相关资源
      最近更新 更多