เทียบเท่ากับ ListView.setEmptyView ใน RecyclerView


89

ในRecyclerViewฉันต้องการตั้งค่ามุมมองว่างให้แสดงเมื่ออะแดปเตอร์ว่างเปล่า มีค่าเทียบเท่าListView.setEmptyView()หรือไม่?


1
ดูRecyclerView setEmptyViewอาจช่วยให้บรรลุผลเช่นเดียวกัน
ρяσѕρєя K

คำตอบ:


69

ด้วยคุณสมบัติการผูกข้อมูลใหม่คุณสามารถทำได้ในเค้าโครงของคุณโดยตรง:

<TextView
   android:text="No data to display."
   android:visibility="@{dataset.size() > 0 ? View.GONE : View.VISIBLE}" />

ในกรณีนี้คุณต้องเพิ่มตัวแปรและนำเข้าไปยังส่วนข้อมูลของ XML ของคุณ:

<data>
<import type="android.view.View"/>
<variable
    name="dataset"
    type="java.util.List&lt;java.lang.String&gt;"
    />
</data>

6
ตัวอย่างข้างต้นถูกทำให้ง่ายขึ้นเพื่อเน้นแนวทางการผูกข้อมูล การผูกข้อมูลมีความยืดหยุ่นมาก แน่นอนคุณสามารถนำเข้าAdapterแทนชุดข้อมูลและการใช้งานของมันgetItemCount()หรือห่อทุกอย่างภายในViewModelและการตั้งค่าไปandroid:visibility viewModel.getEmptyViewVisibility()
André Diermann

5
สิ่งนี้ควรได้รับการโหวตให้สูงขึ้นซึ่งเป็นตัวอย่างที่ยอดเยี่ยมของความสามารถในการผูกข้อมูล
Ed George

1
@javmarina ไม่สำหรับฉันเลย์เอาต์ไม่ได้อัปเดตต่อไป หากอะแดปเตอร์ของฉันเริ่มต้นด้วยขนาด 0 แล้วต่อมาชุดข้อมูลเติบโตขึ้นเค้าโครงจะไม่อัปเดตตามที่ต้องการ ดูเหมือนว่าการผูกข้อมูลจะใช้ไม่ได้กับฉัน :-(
meisteg

4
สิ่งนี้จะอัปเดตแม้ว่าอแดปเตอร์จะเติบโตแบบไดนามิกหรือลดขนาดเป็นศูนย์หรือไม่? ฉันสงสัย.
david

1
@ a11n มันไม่ได้อัปเดตเลย์เอาท์เมื่อรายการย่อขนาดเป็น 0 หรือรับข้อมูลเราต้องตั้งค่าให้กับการโยงจากคลาสทุกครั้งที่เราทำการเปลี่ยนแปลงใด ๆ กับรายการมีวิธีใดในการอัปเดตเลย์เอาต์ด้วยตัวเองหรือไม่?
Om Infowave Developers

116

นี่คือคลาสที่คล้ายกับ @dragon born แต่สมบูรณ์กว่า ขึ้นอยู่กับสาระสำคัญนี้

public class EmptyRecyclerView extends RecyclerView {
    private View emptyView;
    final private AdapterDataObserver observer = new AdapterDataObserver() {
        @Override
        public void onChanged() {
            checkIfEmpty();
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            checkIfEmpty();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            checkIfEmpty();
        }
    };

    public EmptyRecyclerView(Context context) {
        super(context);
    }

    public EmptyRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    void checkIfEmpty() {
        if (emptyView != null && getAdapter() != null) {
            final boolean emptyViewVisible = getAdapter().getItemCount() == 0;
            emptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE);
            setVisibility(emptyViewVisible ? GONE : VISIBLE);
        }
    }

    @Override
    public void setAdapter(Adapter adapter) {
        final Adapter oldAdapter = getAdapter();
        if (oldAdapter != null) {
            oldAdapter.unregisterAdapterDataObserver(observer);
        }
        super.setAdapter(adapter);
        if (adapter != null) {
            adapter.registerAdapterDataObserver(observer);
        }

        checkIfEmpty();
    }

    public void setEmptyView(View emptyView) {
        this.emptyView = emptyView;
        checkIfEmpty();
    }
}

คุณช่วยอธิบายวิธีใช้คลาสนี้ได้ไหม
Ololoking

เหมือนกับที่คุณทำกับ RecyclerView เพียงแค่เพิ่มsetEmptyViewวิธีการที่คุณสามารถเรียกเมื่อใดก็ตามที่คุณต้องการกำหนดมุมมองที่ว่างเปล่า ดูListView.setEmptyViewเอกสารหากไม่ชัดเจนก็เป็นแนวคิดเดียวกัน
Marc Plano-Lesay

5
การใช้งานที่คล้ายกันจากตัวอย่าง Google: github.com/googlesamples/android-XYZTouristAttractions/blob/…
jase


1
@AJW ฉันเดาว่าส่วนใหญ่เป็นเรื่องของสิ่งที่คุณต้องการบรรลุ ความแตกต่างระหว่างการใช้งานทั้งสองนั้นมีน้อยมากและไม่มีเหลือทันทีที่ตั้งค่าอะแดปเตอร์ หากคุณไม่เปลี่ยนอะแดปเตอร์ (ซึ่งอาจเป็นกรณีส่วนใหญ่) ก็ไม่มีความแตกต่าง
Marc Plano-Lesay

26

โซลูชันที่ให้ไว้ในลิงค์นี้ดูเหมือนจะสมบูรณ์แบบ ใช้ viewType เพื่อระบุเวลาที่จะแสดง emptyView ไม่จำเป็นต้องสร้าง RecyclerView แบบกำหนดเอง

การเพิ่มโค้ดจากลิงค์ด้านบน:

package com.example.androidsampleproject;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class RecyclerViewActivity extends Activity {

RecyclerView recyclerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recycler_view);
    recyclerView = (RecyclerView) findViewById(R.id.myList);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(new MyAdapter());
}


private class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<String> dataList = new ArrayList<String>();

    public class EmptyViewHolder extends RecyclerView.ViewHolder {
        public EmptyViewHolder(View itemView) {
            super(itemView);
        }
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView data;

        public ViewHolder(View v) {
            super(v);
            data = (TextView) v.findViewById(R.id.data_view);
        }
    }

    @Override
    public int getItemCount() {
        return dataList.size() > 0 ? dataList.size() : 1;
    }

    @Override
    public int getItemViewType(int position) {
        if (dataList.size() == 0) {
            return EMPTY_VIEW;
        }
        return super.getItemViewType(position);
    }


    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder vho, final int pos) {
        if (vho instanceof ViewHolder) {
            ViewHolder vh = (ViewHolder) vho;
            String pi = dataList.get(pos);
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v;

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

    private static final int EMPTY_VIEW = 10;
}

}

6
ฉันคิดว่าการขยาย RecyclerView เป็นโซลูชันที่เหมาะสมกว่าวิธีนี้เพราะโดยทั่วไปฉันมีอะแดปเตอร์รีไซเคิลจำนวนมากและฉันต้องการหลีกเลี่ยงการเพิ่มตรรกะประเภทนี้ให้กับทุกตัว
ฮัน

นั่นเป็นเหตุผลที่ @Gunhan เมื่อใช้อะแดปเตอร์รีไซเคิลจำนวนมาก คุณอาจลองขยาย BaseAdapter ตัวเดียวที่ปรับแต่งสำหรับสิ่งทั่วไปได้
Sudhasri

2
แม้ว่าคุณจะมีอะแด็ปเตอร์เพียงตัวเดียวและมีมุมมองรีไซเคิลเพียงตัวเดียว แต่ก็ไม่ใช่ความรับผิดชอบของอะแด็ปเตอร์ อะแดปเตอร์อยู่ที่นี่เพื่อแสดงรายการไม่ใช่ไม่มีรายการ
Marc Plano-Lesay

@Kernald ขึ้นอยู่กับกรณีการใช้งานของคุณ โดยส่วนตัวแล้วฉันคิดว่ามันสะอาดกว่าวิธีที่สุดาศรีทำมาก โดยเฉพาะอย่างยิ่งถ้าคุณต้องการแสดงมุมมองที่แตกต่างออกไปในกรณีที่ไม่มีสินค้าเช่น: "ไม่มีสินค้าที่นี่ไปช้อปปิ้ง!" หรืออะไรทำนองนั้น
AgentKnopf

@ Zainodis อย่างที่บอกมันเป็นมุมมองที่แตกต่าง มันไม่ responsability อะแดปเตอร์ซึ่งก็คือการแสดงรายการใน recyclerview ไม่มีอะไรอื่น ฉันยอมรับว่าการพูดอย่างมีเทคนิคทั้งสองวิธีใช้ได้ผลและเท่าเทียมกันมาก แต่รายการของอะแด็ปเตอร์ไม่ได้ถูกสร้างขึ้นเพื่อแสดงมุมมองเช่นนี้
Marc Plano-Lesay

10

ฉันต้องการวิธีง่ายๆเช่น

ให้ RecyclerView ของคุณอยู่ใน FrameLayout หรือ RelativeLayout ด้วย TextView หรือมุมมองอื่น ๆ ที่มีการแสดงข้อความข้อมูลว่างพร้อมการมองเห็น GONE ตามค่าเริ่มต้นจากนั้นในคลาสอะแดปเตอร์ให้ใช้ตรรกะ

ที่นี่ฉันมี TextView หนึ่งรายการที่ไม่มีข้อมูล

@Override
public int getItemCount() {
    textViewNoData.setVisibility(data.size() > 0 ? View.GONE : View.VISIBLE);
    return data.size();
}

3

ลองRVEmptyObserver:

เป็นการใช้งานAdapterDataObserverที่ช่วยให้คุณตั้งค่าViewเป็นเลย์เอาต์ว่างเริ่มต้นสำหรับRecylerViewไฟล์. ด้วยวิธีนี้แทนที่จะใช้แบบกำหนดเองRecyclerViewและทำให้ชีวิตของคุณยากขึ้นคุณสามารถใช้รหัสที่มีอยู่ได้อย่างง่ายดาย:


ตัวอย่างการใช้งาน:

RVEmptyObserver observer = new RVEmptyObserver(recyclerView, emptyView)
rvAdapter.registerAdapterDataObserver(observer);

คุณสามารถดูโค้ดและตัวอย่างการใช้งานในแอพจริงได้ที่นี่


ชั้น:

public class RVEmptyObserver extends RecyclerView.AdapterDataObserver {
    private View emptyView;
    private RecyclerView recyclerView;

    public RVEmptyObserver(RecyclerView rv, View ev) {
        this.recyclerView = rv;
        this.emptyView    = ev;
        checkIfEmpty();
    }

    private void checkIfEmpty() {
        if (emptyView != null && recyclerView.getAdapter() != null) {
            boolean emptyViewVisible = recyclerView.getAdapter().getItemCount() == 0;
            emptyView.setVisibility(emptyViewVisible ? View.VISIBLE : View.GONE);
            recyclerView.setVisibility(emptyViewVisible ? View.GONE : View.VISIBLE);
        }
    }

    public void onChanged() { checkIfEmpty(); }
    public void onItemRangeInserted(int positionStart, int itemCount) { checkIfEmpty(); }
    public void onItemRangeRemoved(int positionStart, int itemCount) { checkIfEmpty(); }
}

2

เวอร์ชันของฉันอ้างอิงจากhttps://gist.github.com/adelnizamutdinov/31c8f054d1af4588dc5c

public class EmptyRecyclerView extends RecyclerView {
    @Nullable
    private View emptyView;

    public EmptyRecyclerView(Context context) { super(context); }

    public EmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); }

    public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private void checkIfEmpty() {
        if (emptyView != null && getAdapter() != null) {
            emptyView.setVisibility(getAdapter().getItemCount() > 0 ? GONE : VISIBLE);
        }
    }

    private final AdapterDataObserver observer = new AdapterDataObserver() {
        @Override
        public void onChanged() {
            checkIfEmpty();
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            checkIfEmpty();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            checkIfEmpty();
        }
    };

    @Override
    public void setAdapter(@Nullable Adapter adapter) {
        final Adapter oldAdapter = getAdapter();
        if (oldAdapter != null) {
            oldAdapter.unregisterAdapterDataObserver(observer);
        }
        super.setAdapter(adapter);
        if (adapter != null) {
            adapter.registerAdapterDataObserver(observer);
        }
        checkIfEmpty();
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);
        if (null != emptyView && (visibility == GONE || visibility == INVISIBLE)) {
            emptyView.setVisibility(GONE);
        } else {
            checkIfEmpty();
        }
    }

    public void setEmptyView(@Nullable View emptyView) {
        this.emptyView = emptyView;
        checkIfEmpty();
    }
}

3
เป็นความคิดที่ดีที่จะนำไปใช้ใหม่setVisibilityด้วย
Marc Plano-Lesay

2

ฉันต้องการใช้ฟังก์ชันนี้ใน Recycler.Adapter

ในเมธอด getItemCount ที่ถูกแทนที่ของคุณให้ใส่รหัสตรวจสอบว่างที่นั่น:

@Override
public int getItemCount() {
    if(data.size() == 0) listIsEmtpy();
    return data.size();
}

3
ไม่ใช่ความรับผิดชอบของอะแดปเตอร์ อะแดปเตอร์อยู่ที่นี่เพื่อแสดงรายการไม่ใช่ไม่มีรายการ
Marc Plano-Lesay

@Kernald รหัสของเราและวิธีการของเราเองเราปรับแต่งและใช้มันอย่างไร
Lalit Poptani

@LalitPoptani นั่นเอง แต่เป็นเว็บไซต์ถาม - ตอบที่ผู้คนกำลังมองหาคำตอบโดยส่วนใหญ่ไม่ได้คิดอะไรมากไปกว่า "ทางลัดการคัดลอกอีกครั้งคืออะไร" การระบุว่าการแก้ปัญหานั้นผิดทางความหมาย (ยิ่งไปกว่านั้นเมื่อคุณมี "สิทธิ์" ในการแก้ปัญหาด้วย) ไม่ได้ไร้ประโยชน์จริงๆ…
Marc Plano-Lesay

@Kernald ดีฉันคิดว่าวิธีนี้เป็นวิธีที่ง่ายที่สุดและเป็นทางออกที่ดีเช่นกันเพราะทุกครั้งที่มีการแจ้งอแด็ปเตอร์สิ่งนี้จะถูกเรียกและสามารถใช้เพื่อตรวจสอบขนาดของข้อมูลได้!
Lalit Poptani

2
@ MarcPlano-Lesay ถูกต้อง คำตอบนี้ไม่สมบูรณ์เนื่องจากไม่ได้จัดการกับกรณีที่จำเป็นต้องมองไม่เห็นมุมมองที่ว่างเปล่าเมื่อมีการเติมรายการ หลังจากนำส่วนนั้นไปใช้โซลูชันนี้จะไม่มีประสิทธิภาพเนื่องจากทุกครั้งที่อะแด็ปเตอร์สอบถามจำนวนรายการsetVisibility()จะถูกเรียก แน่นอนว่าคุณสามารถเพิ่มแฟล็กเพื่อชดเชยได้ แต่นั่นคือเมื่อมันซับซ้อนขึ้น
razzledazzle

2

หากคุณต้องการที่จะสนับสนุนรัฐมากขึ้นเช่นรัฐโหลดรัฐผิดพลาดแล้วคุณสามารถเช็คเอาท์https://github.com/rockerhieu/rv-adapter-states มิฉะนั้นการสนับสนุนมุมมองที่ว่างเปล่าสามารถใช้งานได้อย่างง่ายดายโดยใช้RecyclerViewAdapterWrapperจาก ( https://github.com/rockerhieu/rv-adapter ) ข้อได้เปรียบหลักของแนวทางนี้คือคุณสามารถรองรับมุมมองที่ว่างเปล่าได้อย่างง่ายดายโดยไม่ต้องเปลี่ยนตรรกะของอะแดปเตอร์ที่มีอยู่:

public class StatesRecyclerViewAdapter extends RecyclerViewAdapterWrapper {
    private final View vEmptyView;

    @IntDef({STATE_NORMAL, STATE_EMPTY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface State {
    }

    public static final int STATE_NORMAL = 0;
    public static final int STATE_EMPTY = 2;

    public static final int TYPE_EMPTY = 1001;

    @State
    private int state = STATE_NORMAL;

    public StatesRecyclerViewAdapter(@NonNull RecyclerView.Adapter wrapped, @Nullable View emptyView) {
        super(wrapped);
        this.vEmptyView = emptyView;
    }

    @State
    public int getState() {
        return state;
    }

    public void setState(@State int state) {
        this.state = state;
        getWrappedAdapter().notifyDataSetChanged();
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        switch (state) {
            case STATE_EMPTY:
                return 1;
        }
        return super.getItemCount();
    }

    @Override
    public int getItemViewType(int position) {
        switch (state) {
            case STATE_EMPTY:
                return TYPE_EMPTY;
        }
        return super.getItemViewType(position);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case TYPE_EMPTY:
                return new SimpleViewHolder(vEmptyView);
        }
        return super.onCreateViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        switch (state) {
            case STATE_EMPTY:
                onBindEmptyViewHolder(holder, position);
                break;
            default:
                super.onBindViewHolder(holder, position);
                break;
        }
    }

    public void onBindEmptyViewHolder(RecyclerView.ViewHolder holder, int position) {
    }

    public static class SimpleViewHolder extends RecyclerView.ViewHolder {
        public SimpleViewHolder(View itemView) {
            super(itemView);
        }
    }
}

การใช้งาน:

Adapter adapter = originalAdapter();
StatesRecyclerViewAdapter statesRecyclerViewAdapter = new StatesRecyclerViewAdapter(adapter, emptyView);
rv.setAdapter(endlessRecyclerViewAdapter);

// Change the states of the adapter
statesRecyclerViewAdapter.setState(StatesRecyclerViewAdapter.STATE_EMPTY);
statesRecyclerViewAdapter.setState(StatesRecyclerViewAdapter.STATE_NORMAL);

ฉันใช้รหัสของคุณเป็นพื้นฐานสำหรับโซลูชันที่คล้ายกัน ขอบคุณ!
Albert Vila Calvo

2

ฉันได้แก้ไขสิ่งนี้แล้ว:
สร้างไฟล์ layout layout_recyclerview_with_emptytext.xml
สร้าง EmptyViewRecyclerView.java
---------

EmptyViewRecyclerView emptyRecyclerView = (EmptyViewRecyclerView) findViewById (R.id.emptyRecyclerViewLayout);
emptyRecyclerView.addAdapter (mPrayerCollectionRecyclerViewAdapter "ไม่มีคำอธิษฐานสำหรับหมวดหมู่ที่เลือก");

layout_recyclerview_with_emptytext.xml ไฟล์

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/switcher"
>

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

<com.ninestars.views.CustomFontTextView android:id="@+id/recyclerViewEmptyTextView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="Empty Text"
    android:layout_gravity="center"
    android:gravity="center"
    android:textStyle="bold"
    />

    </merge>


EmptyViewRecyclerView.java

public class EmptyViewRecyclerView extends ViewSwitcher {
private RecyclerView mRecyclerView;
private CustomFontTextView mRecyclerViewExptyTextView;

public EmptyViewRecyclerView(Context context) {
    super(context);
    initView(context);
}

public EmptyViewRecyclerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView(context);
}


private void initView(Context context) {
    LayoutInflater.from(context).inflate(R.layout.layout_recyclerview_with_emptytext, this, true);
    mRecyclerViewExptyTextView = (CustomFontTextView) findViewById(R.id.recyclerViewEmptyTextView);
    mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
}

public void addAdapter(final RecyclerView.Adapter<?> adapter) {
    mRecyclerView.setAdapter(adapter);
    adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            super.onChanged();
            if(adapter.getItemCount() > 0) {
                if (R.id.recyclerView == getNextView().getId()) {
                    showNext();
                }
            } else {
                if (R.id.recyclerViewEmptyTextView == getNextView().getId()) {
                    showNext();
                }
            }
        }
    });
}

public void addAdapter(final RecyclerView.Adapter<?> adapter, String emptyTextMsg) {
    addAdapter(adapter);
    setEmptyText(emptyTextMsg);
}

public RecyclerView getRecyclerView() {
    return mRecyclerView;
}

public void setEmptyText(String emptyTextMsg) {
    mRecyclerViewExptyTextView.setText(emptyTextMsg);
}

}

1
public class EmptyRecyclerView extends RecyclerView {
  @Nullable View emptyView;

  public EmptyRecyclerView(Context context) { super(context); }

  public EmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); }

  public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  void checkIfEmpty() {
    if (emptyView != null) {
      emptyView.setVisibility(getAdapter().getItemCount() > 0 ? GONE : VISIBLE);
    }
  }

  final @NotNull AdapterDataObserver observer = new AdapterDataObserver() {
    @Override public void onChanged() {
      super.onChanged();
      checkIfEmpty();
    }
  };

  @Override public void setAdapter(@Nullable Adapter adapter) {
    final Adapter oldAdapter = getAdapter();
    if (oldAdapter != null) {
      oldAdapter.unregisterAdapterDataObserver(observer);
    }
    super.setAdapter(adapter);
    if (adapter != null) {
      adapter.registerAdapterDataObserver(observer);
    }
  }

  public void setEmptyView(@Nullable View emptyView) {
    this.emptyView = emptyView;
    checkIfEmpty();
  }
}

สิ่งนี้อาจช่วยได้


2
สิ่งนี้ไม่สมบูรณ์ คุณอาจต้องซ่อนRecyclerViewเวลาที่emptyViewมองเห็นได้ (และตรงกันข้าม) นอกจากนี้คุณยังจะต้องโทรcheckIfEmpty()ในและonItemRangeInserted() onItemRangeRemoved()โอ้คุณสามารถอ้างอิงแหล่งที่มาของคุณ: gist.github.com/adelnizamutdinov/31c8f054d1af4588dc5c
Marc Plano-Lesay


1

คุณสามารถวาดข้อความRecyclerViewเมื่อว่างเปล่าได้ กำหนดเองต่อไปนี้ subclass สนับสนุนempty, failed, loadingและofflineโหมด เพื่อการรวบรวมที่ประสบความสำเร็จเพิ่มrecyclerView_stateTextสีสันให้กับทรัพยากรของคุณ

/**
 * {@code RecyclerView} that supports loading and empty states.
 */
public final class SupportRecyclerView extends RecyclerView
{
    public enum State
    {
        NORMAL,
        LOADING,
        EMPTY,
        FAILED,
        OFFLINE
    }

    public SupportRecyclerView(@NonNull Context context)
    {
        super(context);

        setUp(context);
    }

    public SupportRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs);

        setUp(context);
    }

    public SupportRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);

        setUp(context);
    }

    private Paint textPaint;
    private Rect textBounds;
    private PointF textOrigin;

    private void setUp(Context c)
    {
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setColor(ContextCompat.getColor(c, R.color.recyclerView_stateText));

        textBounds = new Rect();
        textOrigin = new PointF();
    }

    private State state;

    public State state()
    {
        return state;
    }

    public void setState(State newState)
    {
        state = newState;
        calculateLayout(getWidth(), getHeight());
        invalidate();
    }

    private String loadingText = "Loading...";

    public void setLoadingText(@StringRes int resId)
    {
        loadingText = getResources().getString(resId);
    }

    private String emptyText = "Empty";

    public void setEmptyText(@StringRes int resId)
    {
        emptyText = getResources().getString(resId);
    }

    private String failedText = "Failed";

    public void setFailedText(@StringRes int resId)
    {
        failedText = getResources().getString(resId);
    }

    private String offlineText = "Offline";

    public void setOfflineText(@StringRes int resId)
    {
        offlineText = getResources().getString(resId);
    }

    @Override
    public void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        String s = stringForCurrentState();
        if (s == null)
            return;

        canvas.drawText(s, textOrigin.x, textOrigin.y, textPaint);
    }

    private void calculateLayout(int w, int h)
    {
        String s = stringForCurrentState();
        if (s == null)
            return;

        textPaint.setTextSize(.1f * w);
        textPaint.getTextBounds(s, 0, s.length(), textBounds);

        textOrigin.set(
         w / 2f - textBounds.width() / 2f - textBounds.left,
         h / 2f - textBounds.height() / 2f - textBounds.top);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);

        calculateLayout(w, h);
    }

    private String stringForCurrentState()
    {
        if (state == State.EMPTY)
            return emptyText;
        else if (state == State.LOADING)
            return loadingText;
        else if (state == State.FAILED)
            return failedText;
        else if (state == State.OFFLINE)
            return offlineText;
        else
            return null;
    }
}

1

จากมุมมองของฉันวิธีที่ง่ายที่สุดในการสร้าง View ที่ว่างเปล่าคือการสร้าง RecyclerView ที่ว่างเปล่าใหม่พร้อมเลย์เอาต์ที่คุณต้องการขยายเป็นพื้นหลัง และอะแดปเตอร์ว่างนี้จะถูกตั้งค่าเมื่อคุณตรวจสอบขนาดชุดข้อมูลของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.