L'actualisation par balayage ne fonctionne pas après avoir défini une vue vide pour listview, qui est le seul enfant d'une lecture par balayage. Comment résoudre ce problème?
Voici la solution: Vous pouvez simplement utiliser cette hiérarchie de vues:
<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>
Ensuite, dans le code, vous appelez simplement:
_listView.setEmptyView(findViewById(Android.R.id.empty));
C'est tout.
J'avais aussi ce problème et je l'ai résolu sans code supplémentaire dans l'activité en utilisant la disposition ci-dessous.
Si vous utilisez une variable ListActivity
ou ListFragment
, elle gère l'affichage/le masquage de la vue vide et actualise les travaux avec une liste vide, ainsi qu'avec cette structure de présentation.
Aucun piratage nécessaire, tout est dans la SwipeRefreshLayout
, comme il se doit.
<?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>
J'espère que cela vous aide. Si c'est le cas, n'oubliez pas d'accepter la réponse.
Note: ceci est un duplicata de ma réponse à cette question , mais cette question est quasiment un duplicata de cette question ... :)
UPDATE
Si SwipeRefreshLayout est activé trop tôt, vous pouvez implémenter ListView.OnScroll avec:
_refresher.Enabled = e.FirstVisibleItem == 0;
Cela désactive le rappel jusqu'à ce que vous ayez fait défiler vers le haut Ceci n’est nécessaire que si vous utilisez un ListView, le nouveau RecyclerView fonctionne comme prévu.
Le problème pour moi était que lorsque la vue vide était visible, le cercle de rafraîchissement n'était pas affiché bien que la méthode de rafraîchissement fonctionne. Pour moi, ce code a fonctionné, j'espère que cela aide.
la mise en page 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>
le SwipeRefreshLayout personnalisé:
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);
}
}
et dans mon Fragment où j'utilise la présentation, je règle uniquement le glissement pour actualiser la présentation de la manière suivante:
mSwipeRefreshLayout.setListView(mListView);
la vue vide de ListView est définie de la manière suivante:
TextView emptyView = (TextView) view.findViewById(R.id.empty_view);
emptyView.setText("No data");
mListView.setEmptyView(emptyView);
J'espère que ça aide.
voici comment j'ai fait cela (solution probablement pas très élégante)
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();
}
}
mise en page vide
<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" />
mise en page
<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>
J'ai résolu ce problème en utilisant deux SwipeToRefreshLayouts.
J'ai posté mon code sur GitHub .
Vous pouvez vérifier ce problème. J'ai posté une solution de contournement.
Comme @Dinesh écrit ci-dessus, j'ai utilisé clickable="true"
comme ci-dessous avec RecyclerView
vide:
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setClickable(true);
myText.setVisibility(View.VISIBLE);
mise en page xml:
<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
a la hauteur match_parent
et SwipeRefresh
a wrap_content
. Quand il y a un élément dans la liste, n'oubliez pas de faire du texte gone
.
J'ai une autre idée qui fonctionne bien. Sous-classe ListView et dérogation setAdapter () et setEmptyView () . setEmptyView devrait simplement être stocké la vue à utiliser pour la vue vide et setAdapter doit enregistrer un DataSetObserver qui masque/affiche la vue vide sans modifier la visibilité de la vue liste. Vous voudrez probablement utiliser un FrameLayout qui contient votre SwipeToRefreshLayout et une vue vide (en tant que frères et soeurs). Vous pouvez ensuite positionner la vue vide en haut/au milieu/en bas, etc., assez facilement en utilisant la gravité et la gravité de présentation. Vous pouvez également utiliser un RelativeLayout mais je n'ai pas essayé. Vous voudrez peut-être en quelque sorte désenregistrer le dataSetObserver. Je pense que vous voudrez peut-être le faire dans onDetachFromWindow, comme je l'ai fait ci-dessous.
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);
}
}
}
Exemple de fichier de mise en page:
<?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>
Bien que cela prenne un peu plus de code que simplement sous-classer ListView et modifier setVisibility de manière à ce que la liste ne soit pas définie sur GONE/HIDDEN, je sens que cela est moins complexe et permet toujours à l'utilisateur de définir la liste sur GONE/Hidden. s'ils avaient besoin.