에서는 RecyclerView
어댑터가 비어있을 때 표시 할 빈보기를 설정하고 싶습니다. 에 상응하는 것이 ListView.setEmptyView()
있습니까?
에서는 RecyclerView
어댑터가 비어있을 때 표시 할 빈보기를 설정하고 싶습니다. 에 상응하는 것이 ListView.setEmptyView()
있습니까?
답변:
새로운 데이터 바인딩 기능을 사용 하면 레이아웃에서 직접이 작업을 수행 할 수도 있습니다.
<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<java.lang.String>"
/>
</data>
Adapter
데이터 세트 대신을 가져 와서 사용 getItemCount()
하거나 a 내에서 모든 것을 래핑 ViewModel
하고로 설정할 android:visibility
수 viewModel.getEmptyViewVisibility()
있습니다.
@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();
}
}
setEmptyView
빈 뷰를 정의하고 싶을 때마다 호출 할 수 있는 메서드 만 추가합니다 . ListView.setEmptyView
명확하지 않은 경우 문서를 참조하십시오 . 동일한 아이디어입니다.
이 링크에 제공된 솔루션 은 완벽 해 보입니다. 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;
}
}
나는 단순히 다음과 같은 간단한 해결책을 선호합니다.
RecyclerView를 FrameLayout 또는 RelativeLayout 안에 TextView 또는 기타 뷰와 함께 표시하고 기본적으로 가시성이 GONE 인 빈 데이터 메시지를 표시 한 다음 어댑터 클래스에서 논리를 적용합니다.
여기에 데이터가없는 메시지가있는 TextView가 하나 있습니다.
@Override
public int getItemCount() {
textViewNoData.setVisibility(data.size() > 0 ? View.GONE : View.VISIBLE);
return data.size();
}
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(); }
}
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();
}
}
setVisibility
것도 좋은 생각 입니다.
Recycler.Adapter에서이 기능을 구현하고 싶습니다.
재정의 된 getItemCount 메서드에서 빈 확인 코드를 삽입합니다.
@Override
public int getItemCount() {
if(data.size() == 0) listIsEmtpy();
return data.size();
}
setVisibility()
호출 되기 때문에이 솔루션은 비효율적 입니다. 물론 보상을 위해 몇 가지 플래그를 추가 할 수는 있지만 그 때가 더 복잡해집니다.
로드 상태, 오류 상태와 같은 더 많은 상태를 지원 하려면 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);
이 문제를 해결했습니다.
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);
}
}
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();
}
}
이와 같은 것이 도움이 될 수 있습니다
RecyclerView
때 emptyView
(그리고 그 반대) 를 숨겨야 할 것입니다 . 또한 호출해야합니다 checkIfEmpty()
에 onItemRangeInserted()
와 onItemRangeRemoved()
. : 아, 그리고 당신은 당신의 소스 인용 한 수 gist.github.com/adelnizamutdinov/31c8f054d1af4588dc5c
나는 이것이 ErrorView와 EmptyView 모두에서 더 완전하다고 생각합니다 https://gist.github.com/henrytao-me/2f7f113fb5f2a59987e7
RecyclerView
비어있을 때 텍스트를 칠할 수 있습니다 . 다음 사용자 정의 서브 클래스 지원 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;
}
}
내 관점에서 빈 뷰를 수행하는 가장 쉬운 방법은 배경으로 부풀리고 싶은 레이아웃으로 새로운 빈 RecyclerView를 만드는 것입니다. 그리고이 빈 어댑터는 데이터 세트 크기를 확인할 때 설정됩니다.