RecyclerView添加EmptyView [英] RecyclerView add EmptyView

查看:232
本文介绍了RecyclerView添加EmptyView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在RecyclerView Adapter上实现EmptyView,但是没有得到任何结果.

I'm trying to implement an EmptyView on my RecyclerView Adapter but I'm not getting any result.

我已遵循此教程提示,但没有人为我工作.

I've followed this tutorial and this tip, but noone worked for me.

我已经实现:

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;

但是它不允许我编译,因为它们是不同的ViewHolder,因为我创建了两个ViewHolder类,但是它们是extends Recycler.ViewHolder,所以我不明白...

But it doesn't let me compile because they are differents ViewHolder, because I've created two ViewHolder classes but they extends Recycler.ViewHolder so I don't get it...

我正在尝试执行此操作,因为我有一个SearchView,并且我希望当列表为空时它显示一个EmptyView,我已经通过编程方式进行了此操作,但是我更喜欢添加一个layout,因为我不太了解如何以编程方式放置TextViewsButtons.

I'm trying to do this because I've got a SearchView and I want when the list is empty it shows an EmptyView, I've got it doing it programmatically but I prefer to add like a layout because I don't know that much how to put TextViews and Buttons programmatically.

如果我放

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

它给我错误,因为索引为0.

It gives to me error because index is 0.

我调试了viewType并始终为1,那么它将不符合if条件...

I've debugged the viewType and always is 1, then it won't join the if condition...

深入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;
 }

但事实是,值没有变化.

But the thing is that no changes the value.

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

I almost done it, I did this :

 @Override
public int getItemViewType(int position) {

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

但是有时候,当size()为0时,它返回0 ...我不明白,我使用的是

But sometimes it returns 0 when the size() is 0... I don't get it, I'm using this SearchView, and sometimes when I type a letter that doesn't matches with any item of the list it doesn't show and sometimes it does...

发生的另一件事是,当layout弹出窗口显示在center上时,它显示在屏幕的left上,但是我认为RecyclerView存在问题,因为layout放在里面.

Also other thing that happens is that when the layout popups it shows on the left of the screen when I put that is on center, but I think it's problem with RecyclerView because the layout puts inside of it.

RecyclerView布局:

RecyclerView layout :

<?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>

这是我的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>

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

The other way that I thought is to implement it programmatically as follow :

   @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答案添加视图,但我会就像在Adapter上执行此操作一样,我知道了,但是即使list为空,也不总是显示view.

PROBLEMS

-I only add the view using the @Jimeux answer but I'd like to do this on the Adapter, I got it, but not always shows the view even if the list is empty.

-当时将emptyview.xml放置在RecyclerView内部,然后由于我已将所有<​​c24>放置在中央,因此它显示在右侧.我试图以编程方式添加xml,但这就像一片混乱....

-At the time to put the emptyview.xml it puts inside of the RecyclerView then since I've put all of this xml at the center it shows on the right. I've tried to add the xml programmatically but it's like a chaos....

推荐答案

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

Since you need to handle two different kind of views, it would be easier to use an intermediate list of business object for more easily binding them with views. Idea is to have a kind of placeholder in your list for representing empty state. Defining an intermediate layer is extremely useful in this sense for allowing you to consider eventual changes to be applied to your list in future (e.g. adding you element types). Moreover in this way you can more clearly separate your business model from ui representation (for example you can implement methods returning ui settings based on internal status of model objects).

您可以按照以下步骤进行操作:

You can proceed as follows:

  1. 为列表项(例如ListItem)定义专用的抽象类型,以包装您的业务对象.它的实现可能是这样的:

  1. Define a dedicated abstract type for List items (e.g. ListItem) to wrap your business objects. Its implementation could be something like this:

public abstract class ListItem {

    public static final int TYPE_EMPTY = 0;
    public static final int TYPE_MY_OBJ = 1;

    abstract public int getType();

}  

  • 为每种List元素类型定义一个类:

  • Define a class for each of your List element type:

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

  • 创建您的列表.

  • Create your list.

    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适配器内部或外部进行操作,但是正确处理最终的修改非常重要.这对于利用适配器通知方法至关重要.例如,如果您在适配器中创建列表,则它可能还应该提供添加或删除模型项的方法.例如:

    This is the most important part of code. You have many options for creating this list. You can do it inside your RecyclerView Adapter or outside, but it's extremely important to properly handle eventual modifications to it. This is essential for exploiting Adapter notify methods. For example, if you create list within the Adapter, it should probably provide also methods for adding or removing your model items. For example:

    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方法:

  • Define an adapter for your RecyclerView, working on List defined at point 3. Here what is important is to override getItemViewType method as follows:

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

  • 此外,ViewHolder的类型应为RecyclerView.ViewHolder(除非您即使在这种情况下也决定创建中间类).

    Moreover, type of ViewHolder should be RecyclerView.ViewHolder (unless you decide to create an intermediate class even in this case).

    1. 然后,您需要具有两个布局以及用于空对象和业务obj项目的ViewHolder.适配器方法应相应地注意这一点:

    1. Then you need to have two layouts and ViewHolder for empty and business obj items. Adapter methods should take care of this accordingly:

    @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类型并为其创建一个特定的配置,该配置代表一个空的占位符.这种方法可能不是最好的方法,以防将来您需要通过添加例如新的列表项类型来使逻辑更加复杂.

    Of course, as I wrote at the beginning you don't need to strictly define intermediate types for ui representation (EmptyItem and MyObjItem). You can even just use MyObj type and create a specific configuration for it that represent an empty placeholder. This approach is probably not the best in case in future you need to make your logic more complex by including for example new list item types.

    这篇关于RecyclerView添加EmptyView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆