当前位置: 首页 > 知识库问答 >
问题:

回收器视图添加空视图

赵智
2023-03-14

我正在尝试在我的 RecyclerView 适配器上实现 EmptyView,但我没有得到任何结果。

我遵循了这个教程和这个技巧,但是没有人为我工作。

我已经实现了:

if (viewType == EMPTY_VIEW) {
    v = LayoutInflater.from(parent.getContext()).inflate(R.layout.empty_view, parent, false);
    EmptyViewHolder evh = new EmptyViewHolder(v);
    return evh;
}

v = LayoutInflater.from(parent.getContext()).inflate(R.layout.data_row, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;

但它不让我编译,因为它们是不同的< code > viewmoder ,因为我创建了两个< code > viewmoder 类,但它们< code >扩展了Recycler。ViewHolder所以我不明白...

我正在尝试这样做,因为我有一个SearchView,我希望当列表为空时,它会显示一个EmpqueView,我已经让它以编程方式完成,但我更喜欢像布局一样添加,因为我不知道如何以编程方式放置TextViewsButtons

同样,如果我把

return dataList.size() > 0 ? dataList.size() : 1;

它给我错误,因为索引是0。

我已经调试了viewType并且始终是1,那么它不会加入if条件...

在< code>Android上,我发现了这个:

/**
 * Return the view type of the item at <code>position</code> for the purposes
 * of view recycling.
 *
 * <p>The default implementation of this method returns 0, making the assumption of
 * a single view type for the adapter. Unlike ListView adapters, types need not
 * be contiguous. Consider using id resources to uniquely identify item view types.
 *
 * @param position position to query
 * @return integer value identifying the type of the view needed to represent the item at
 *                 <code>position</code>. Type codes need not be contiguous.
 */
 public int getItemViewType(int position) {
    return 0;
 }

但事实是no改变了这个值。

我几乎做到了,我做到了:

 @Override
public int getItemViewType(int position) {

    return list.size() > 0 ? list.size() : 1;
}

但有时当 size() 为 0 时,它会返回 0...我不明白,我正在使用这个SearchView,有时当我键入与列表中任何项目都不匹配的字母时,它不会显示,有时它会显示...

发生的另一件事是,当我将布局弹出窗口放在屏幕左侧时,它会显示在屏幕的左侧,但我认为这是RecyclizerView的问题,因为布局放在其中。

RecyclerView视图布局:

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:id="@+id/rtpew"
    android:layout_centerInParent="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    >
         <LinearLayout android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:id="@+id/linearpew">
            <android.support.v7.widget.RecyclerView
             android:id="@+id/rv"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
            />
         </LinearLayout>
 </RelativeLayout>

这是我的< code>emptylayout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true">
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/ImageViewSearchFail"
    android:src="@drawable/sadface"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:layout_gravity="center"
    android:textSize="@dimen/15dp"
    android:layout_marginTop="4dp"
    android:text="foo"
    android:layout_below="@+id/ImageViewSearchFail"
    android:layout_centerHorizontal="true" />
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/ButtonAddEntity"
    android:text="foo"
    android:background="?android:selectableItemBackground"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true" />
</RelativeLayout>

我想到另一种方法是以编程方式实现它,如下所示:

   @Override
public boolean onQueryTextChange(String query) {
    final ArrayList<List> filteredModelList = filter(mModel, query);
        mAdapter.animateTo(filteredModelList);
        rv.scrollToPosition(0);
    if(query.isEmpty()){
            //Here
    }
  return true;
}

和:

private ArrayList<List> filter(ArrayList<List> models, String query) {
    query = query.toLowerCase();
    final ArrayList<List> filteredModelList = new ArrayList<List>();
    for (List model : models) {
        final String text = model.getRedName().toLowerCase();
        if (text.contains(query)) {
            filteredModelList.add(model);
        }
    }
    if (filteredModelList.size()<0) {
           //HERE
    }
    else{
           //Delete the views added
    }
    return filteredModelList;
}

-我只使用@Jimeux答案添加视图,但我想在< code >适配器上这样做,我知道,但即使< code >列表为空,也不总是显示< code >视图。

-在将< code>emptyview.xml放入< code > recycle view 中时,由于我已将所有< code>xml放在中间,它显示在右侧。我试图以编程方式添加< code>xml,但是它看起来很混乱....

共有3个答案

拓拔曦
2023-03-14

编译错误可能是由于您使用主 ViewHolder 作为泛型参数扩展 RecyclerView.Adapter 而导致的。

YourAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>

然后适当地投射你的ViewHolders(你可以在这里重用getViewType(position)。)。请务必在方法中切换 ViewHolder 类型。

彭骏
2023-03-14

请按照以下步骤逐个操作

由于 RecyclerView 项目有两种类型的视图,因此您的适配器声明应如下所示

public class YourAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 

和列表视图项和空视图的 ViewHolders 应该像这样扩展 RecyclerView.ViewHolder

 static class ListItemViewHolder extends RecyclerView.ViewHolder {

        public ListItemViewHolder(View itemView) {
            super(itemView);
            // initialize your views here for list items
        }
    }

static class EmptyViewViewHolder extends RecyclerView.ViewHolder {

        public EmptyViewViewHolder(View itemView) {
            super(itemView);
            // initialize your views here for empty list
        }
    }

2).您必须< code >覆盖 < code > getItemCount()和< code>getItemViewType()

@Override
    public int getItemCount() {
        return yourList.size() > 0 ? yourList.size() : 1;// if size of your list is greater than 0, you will return your size of list otherwise 1 for the empty view.
    }

    @Override
    public int getItemViewType(int position) {
        if (yourList.size() == 0) {
            return VIEW_TYPE_EMPTY;
        }
        return position;
    }

3).您的< code > onCreateViewHolder()现在看起来会像这样

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == VIEW_TYPE_EMPTY) {
        return new EmptyViewViewHolder(mLayoutInflater
                .inflate(R.layout.empty_view_layout, parent, false));
    } else {
        return new ListItemViewHolder(mLayoutInflater
                .inflate(R.layout.row_list_item, parent, false));
    }
}

4).您还必须在< code>onBindViewHolder()中应用相同的检查

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == VIEW_TYPE_EMPTY) {
            EmptyViewViewHolder emptyViewViewHolder = (EmptyViewViewHolder) holder;
            // set values for your empty views
        } else {
            ListItemViewHolder listItemViewHolder = (ListItemViewHolder) holder;
            // set values for your list items
        }
    }

5).最后< code >覆盖您的< code > search view . setonquerytextlistener()

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                currentSearchKeyword = newText.trim();
                if(currentSearchKeyword.iseEmpty()){
                    yourList.clear();
                    yourAdapter.notifyDataSetChanged();
                }else{
                   // there will two cases again 1). If your currentSearchKeyword matchces with list results, add that items to your list and notify your adapter. 2) If the currentSearchKeyword doesn't matched with list results, clear your list and notify your adapter;
                }
                return false;
            }
        });

希望它能帮助你,如果有任何问题,请告诉我。

空佐
2023-03-14

由于您需要处理两种不同类型的视图,因此使用业务对象的中间列表可以更轻松地将它们与视图绑定。想法是在列表中有一种占位符来表示空状态。从这个意义上说,定义中间层非常有用,因为它允许您考虑将来应用于列表的最终更改(例如,添加元素类型)。此外,通过这种方式,您可以更清楚地将业务模型与ui表示形式分开(例如,您可以实现基于模型对象的内部状态返回ui设置的方法)。

您可以按以下步骤操作:

>

  • 为列表项(例如 ListItem)定义专用的抽象类型以包装业务对象。它的实现可能如下所示:

    public abstract class ListItem {
    
        public static final int TYPE_EMPTY = 0;
        public static final int TYPE_MY_OBJ = 1;
    
        abstract public int getType();
    
    }  
    

    为每个列表元素类型定义一个类:

    public class EmptyItem extends ListItem {
    
        @Override
        public int getType() {
            return TYPE_EMPTY;
        }
    
    }
    
    public class MyObjItem extends ListItem {
    
        private MyObj obj;
    
        public ContactItem(MyObj obj) {
            this.obj = obj;
        }
    
        public MyObj getMyObj() {
            return obj;
        }
    
        // here you can also add methods for simplify
        // objects rendering (e.g. get background color
        // based on your object internal status)
    
        @Override
        public int getType() {
            return TYPE_MY_OBJ;
        }
    
    }
    

    创建您的列表。

    List<ListItem> mItems = new ArrayList<>();
    if (dataList != null && dataList.size() > 0) {
        for (MyObj obj : dataList) {
            mItems.add(new MyObjItem(obj));
        }
    } else {
        mItems.add(new EmptyItem());
    }
    

    这是代码中最重要的部分。创建这个列表有很多选择。您可以在RecyclerView适配器内部或外部执行此操作,但是正确处理对它的最终修改非常重要。这对于利用适配器通知方法是必不可少的。例如,如果您在适配器中创建列表,那么它可能还会提供添加或删除模型项的方法。例如:

    public void addObj(MyObj obj) {
        if (mItems.size() == 1 && mItems.get(0).getType() == ListItem.EMPTY_TYPE) {
            mItems.clear();
        }
        mItems.add(new MyObjItem(obj));
        notifyDataSetChanged();
    } 
    

    为 RecyclerView 定义一个适配器,处理在第 3 点定义的 List。这里重要的是重写getItemViewType方法,如下所示:

    @Override
    public int getItemViewType(int position) {
        return mItems.get(position).getType();
    }
    

    此外,ViewHolder 的类型应该是 RecyclerView.ViewHolder(除非您决定创建一个中间类,即使在这种情况下)。

    然后,您需要有两个布局和视图持有人的空白和业务对象项目。适配器方法应该相应地解决这个问题:

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == ListItem.TYPE_EMPTY) {
            View itemView = mLayoutInflater.inflate(R.layout.empty_layout, parent, false);
            return new EmptyViewHolder(itemView);
        } else {
            View itemView = mLayoutInflater.inflate(R.layout.myobj_layout, parent, false);
            return new MyObjViewHolder(itemView);
        }
    }
    
    
    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {
        int type = getItemViewType(position);
        if (type == ListItem.TYPE_EMPTY) {
            EmptyItem header = (EmptyItem) mItems.get(position);
            EmptyViewHolder holder = (EmptyViewHolder) viewHolder;
            // your logic here... probably nothing to do since it's empty
        } else {            
            MyObjItem event = (MyObjItem) mItems.get(position);
            MyObjViewHolder holder = (MyObjViewHolder) viewHolder;
            // your logic here
        }
    }
    

    当然,正如我在开始时所写的,你不需要严格定义ui表示的中间类型(EmptyItem和MyObjItem)。您甚至可以只使用MyObj类型并为其创建表示空占位符的特定配置。此方法可能不是最好的方法,以防将来需要通过包含例如新的列表项类型来使逻辑更加复杂。

  •  类似资料:
    • 我想添加一个headerview,当用户向下滚动时隐藏,当用户向上滚动时再次显示。 例子:https://imgur.com/a/tTq70B0 正如你在链接中看到的“你写的是……”pharase仅在用户滚动到顶部时显示。Android sdk中有类似的东西吗? 我怎样才能做到同样的事?

    • 我能够从URL发送JSON响应,然后当我在RecyclerView上显示相同的响应时,得到的输出是空白的,但选项卡和导航抽屉仍然存在。运行该应用程序时也没有错误。我也在使用截击库。 问题:我在列出服务的RecylerView上没有得到任何输出。我会在这里贴出与RecyclerView相关的代码。另外,我已经在底部发布了堆栈跟踪。 serviceViewAdapter.java(适配器) fragm

    • 在其他回收器视图中有一个回收器视图。两者都需要垂直滚动。外部回收器视图滚动正常,但内部回收器视图滚动不正常。 这是代码: ViewAdapter如下: 我尝试了以下两种回收商观点,但都无法解决问题 也尝试了这个:

    • 当我尝试将Image URL解析到ImageView中时,回收器视图不显示,活动为空。我正在使用Picasso将图像加载到适配器类中的onBinfViewHolder方法中。这是相关代码 代表: } RepRvAdapter: } 解析JSON数据的方法: 现在,我有一行解析图像URL的代码被注释掉了。行取消注释后,活动将不再显示。如何获取要在ImageView中解析和显示的图像url?我认为这可

    • 我刚开始在firebase工作。我设法上传了文本和图像,但是,我无法检索要显示在回收器视图中的图像,只能检索文本。我用的是毕加索依赖。我已经包括了我的主要活动。java类,该类负责显示从问题“我的适配器”中的firebase检索的回收器视图项。java类和模型类。我相信,在我将图像URI上载到firebase存储时,我可能犯了没有存储图像URI的错误,因此适配器无法检索图像位置。我想这可能是因为我