Подтвердить что ты не робот

Поддержка Android v4 SwipeRefreshLayout проблема с пустым представлением

SwipeRefresh не работает после установки пустого представления для listview, который является единственным дочерним элементом макета SwipeRefresh. Как решить эту проблему?

4b9b3361

Ответ 1

Вот решение: Вы можете просто использовать эту иерархию представлений:

    <FrameLayout ...>

        <android.support.v4.widget.SwipeRefreshLayout ...>

            <ListView
                android:id="@android:id/list" ... />
        </android.support.v4.widget.SwipeRefreshLayout>

        <TextView
            android:id="@android:id/empty" ...
            android:text="@string/empty_list"/>
    </FrameLayout>

Затем в коде вы просто вызываете:

_listView.setEmptyView(findViewById(android.R.id.empty));

Что это.

Ответ 2

У меня тоже была эта проблема, и я решил без какого-либо дополнительного кода в действии, используя макет ниже.

Если вы используете ListActivity или ListFragment, он обрабатывает отображение/скрытие пустого представления для вас и обновляет работу с пустым списком также с этой структурой компоновки.

Никаких взломов не требуется, все в SwipeRefreshLayout, как и должно быть.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/Refresher"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@null" />
        <ScrollView
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:text="Geen formulieren gevonden"
                style="@style/text.EmptyView" />
        </ScrollView>
    </LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>

Надеюсь, это поможет вам. Если да, не забудьте принять ответ.

Примечание: это дубликат моего ответа на этот вопрос, но этот вопрос в значительной степени дублирует этот вопрос...:)

UPDATE
Если SwipeRefreshLayout активирован слишком рано, вы можете реализовать ListView.OnScroll с помощью:

_refresher.Enabled = e.FirstVisibleItem == 0;

Это отключает обновление до прокрутки вверх. Это необходимо только при использовании ListView, новый RecyclerView работает так, как ожидалось.

Ответ 3

Проблема для меня заключалась в том, что, когда пустой вид был видимым, освежающий круг не показывался, хотя метод обновления работал. Для меня этот код работал, я надеюсь, что это поможет.

  • расположение xml:

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true">
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fadingEdge="none"
            android:footerDividersEnabled="false"
            android:headerDividersEnabled="false"/>
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center">
    
            <TextView
                android:id="@+id/empty_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:visibility="gone"/>
        </ScrollView>
    </FrameLayout>
    

  • пользовательский SwipeRefreshLayout:

    package misc;
    
    import android.content.Context;
    import android.support.v4.widget.SwipeRefreshLayout;
    import android.widget.ListView;
    
    public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {
        private ListView mListView;
    
        public CustomSwipeRefreshLayout(Context context) {
            super(context);
        }
    
        public void setListView(ListView listView) {
            mListView = listView;
        }
    
        @Override
        public boolean canChildScrollUp() {
            if (mListView == null) {
                return true;
            }
    
            return mListView.canScrollVertically(-1);
        }
    }
    
  • а в моем фрагменте, где я использую макет, я устанавливаю только салфетки для обновления макета следующим образом:

    mSwipeRefreshLayout.setListView(mListView);
    
  • Пустое представление ListView установлено таким образом:

    TextView emptyView = (TextView) view.findViewById(R.id.empty_view);
    emptyView.setText("No data");
    mListView.setEmptyView(emptyView);
    

Надеюсь, это поможет.

Ответ 4

вот как я это сделал (возможно, не очень изящное решение)

private void createEmptyView() {
    ViewGroup parent = (ViewGroup) listView.getParent();
    emptyView = (TextView) getLayoutInflater(null)
            .inflate(R.layout.view_empty, parent, false);
    parent.addView(emptyView);
    listView.setEmptyView(emptyView);
}

public class FrameSwipeRefreshLayout extends SwipeRefreshLayout {

    private ViewGroup listView;
    public void setListView(ViewGroup list) {
        listView = list;
    }

    @Override
    public boolean canChildScrollUp() {
        if (listView != null) {
            View child = listView.getChildAt(0);
            return child != null && child.getTop() != 0;
        }
        return super.canChildScrollUp();
    }
}

пустой макет

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center_horizontal"
      android:clickable="true" />

список макетов

    <FrameSwipeRefreshLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >
        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
        </FrameLayout>
    </FrameSwipeRefreshLayout>

Ответ 6

Я исправил эту проблему, используя два SwipeToRefreshLayouts.

  • Один для упаковки ListView
  • Другое как emptyView

Я разместил свой код на GitHub.

Ответ 7

Как написано выше @Dinesh, я использовал clickable="true", как показано ниже, с пустым RecyclerView:

mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setClickable(true);
myText.setVisibility(View.VISIBLE);

xml layout:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshKartvizitKisilerim"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

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


    <TextView
        android:id="@+id/myText"
        android:visibility="gone"
        android:text="@string/noListItem"
        android:textSize="18sp"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

RecyclerView имеет высоту match_parent и SwipeRefresh имеет wrap_content. Когда в списке есть элемент, не забудьте сделать текст gone.

Ответ 8

У меня есть другая идея, которая хорошо работает. Подкласс ListView и переопределить setAdapter() и setEmptyView(). setEmptyView должен просто сохранить вид, который будет использоваться для пустого представления, и setAdapter должен зарегистрировать DataSetObserver, который будет скрывать/показывать пустой вид, не изменяя видимость вида списка. Вероятно, вы захотите использовать FrameLayout, в котором содержится SwipeToRefreshLayout и пустой вид (как братья и сестры). Затем вы можете позиционировать пустой вид в верхней/средней/нижней и т.д. Довольно легко, используя гравитацию и гравитацию макета. Вы также можете использовать RelativeLayout, но я не пробовал. Вы захотите каким-то образом отменить регистрацию dataSetObserver, я думаю, вы можете сделать это в onDetachFromWindow, как я сделал ниже.

public class SwipeToRefreshCompatibleList extends ListView {

    private boolean mIsEmpty = false;
    private View mEmptyView;
    private Adapter mAdapter;

    private DataSetObserver mLocalObserver = new  DataSetObserver() {
        @Override
        public void onChanged() {
            boolean isEmpty = mAdapter == null || mAdapter.getCount() == 0;
            if (mEmptyView != null) {
                if (isEmpty != mIsEmpty) {
                    mEmptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
                }
            }
            mIsEmpty = isEmpty;
        }
    };

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

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

    public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        mAdapter = adapter;
        adapter.registerDataSetObserver(mLocalObserver);
        super.setAdapter(adapter);
    }


    @Override
    public void setEmptyView(View view) {
        mEmptyView = view;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mLocalObserver);
        }
    }

}

Пример файла макета:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >

            <com.company.widget.SwipeToRefreshCompatibleList
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/BasicList"
                android:divider="@null"
                />


        </android.support.v4.widget.SwipeRefreshLayout>

        <TextView
            android:padding="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:id="@android:id/empty"
            />

    </FrameLayout>

В то время как для этого требуется немного больше кода, чем просто подклассификация ListView и изменение setVisibility, так что он не будет устанавливать список в GONE/HIDDEN, я чувствую, что это меньше взломать и по-прежнему позволяет пользователю установить список GONE/Hidden, если нужно.

Ответ 9

Я попытался взломать пользовательский интерфейс, но это не сработало, единственное решение - установить адаптер. передайте пустое значение, убедитесь, что оно не будет нулевым.

NotificationListAdapter notificationListAdapter;
notificationListAdapter = new NotificationListAdapter(mContext,notificationResponse);
reCycleViewNotificationList.setAdapter(notificationListAdapter); // weather ListView or RecyclerView