web-dev-qa-db-fra.com

SwiperefreshLayout dans Android

j'utiliseSwipeRefreshLayoutdans ma mise en page ci-dessous:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
  Android:layout_width="wrap_content"
  Android:layout_height="wrap_content"
  Android:background="@color/homePageBackground"
  Android:orientation="vertical" >


<Android.support.v4.widget.SwipeRefreshLayout
    Android:id="@+id/swipeRefreshLayout_listView"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" >

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical" >
<fragment
        Android:id="@+id/announcementHomefragment"
        Android:name="in.test.app.AnnouncementFragment"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content" />
        <ScrollView
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:background="@color/homePageBackground" >

            <RelativeLayout
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:layout_marginBottom="15dp"
                Android:background="@color/homePageBackground" >

                <TextView
                    Android:id="@+id/newsTitle"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_gravity="center"
                    Android:layout_marginLeft="15dp"
                    Android:layout_marginTop="5dp"
                    Android:gravity="center"
                    Android:text="@string/new_list"
                    Android:textAppearance="?android:attr/textAppearanceSmall"
                    Android:textColor="@color/white"
                    Android:textStyle="bold" />

                <fragment
                    Android:id="@+id/newshomefragment"
                    Android:name="in.test.app.NewsFragment"
                    Android:layout_width="wrap_content"
                    Android:layout_height="190dp"
                    Android:layout_below="@id/newsTitle"
                    Android:layout_marginTop="-15dp" />

                <TextView
                    Android:id="@+id/productTitle"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_below="@id/newshomefragment"
                    Android:layout_gravity="center"
                    Android:layout_marginLeft="15dp"
                    Android:layout_marginTop="5dp"
                    Android:gravity="center"
                    Android:text="@string/product_in_home"
                    Android:textAppearance="?android:attr/textAppearanceSmall"
                    Android:textColor="@color/white"
                    Android:textStyle="bold" />

                <fragment
                    Android:id="@+id/proCategoryhomefragment"
                    Android:name="in.test.app.CategoryFragment"
                    Android:layout_width="wrap_content"
                    Android:layout_height="170dp"
                    Android:layout_below="@id/productTitle"
                    Android:layout_marginTop="-15dp" />

                <TextView
                    Android:id="@+id/trainingTitle"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_below="@id/proCategoryhomefragment"
                    Android:layout_gravity="center"
                    Android:layout_marginLeft="15dp"
                    Android:layout_marginTop="2dp"
                    Android:gravity="center"
                    Android:text="@string/trainings_in_home"
                    Android:textAppearance="?android:attr/textAppearanceSmall"
                    Android:textColor="@color/white"
                    Android:textStyle="bold" />

                <fragment
                    Android:id="@+id/trainingfragment"
                    Android:name="in.test.app.TrainingFragment"
                    Android:layout_width="match_parent"
                    Android:layout_height="180dp"
                    Android:layout_below="@id/trainingTitle"
                    Android:layout_marginBottom="10dp"
                    Android:layout_marginTop="-15dp" />
            </RelativeLayout>
        </ScrollView>
    </LinearLayout>
</Android.support.v4.widget.SwipeRefreshLayout>

Quand je descends ma SwipeRefreshLayout cela fonctionne, mais comme vous pouvez le voir dans le code ci-dessus, j'ai une vue de défilement à l'intérieur. Donc, lorsque je descends ma vue de défilement, elle s’écroule et la moitié des images ne s’affiche pas car elle est tombée. Quand j'essaie de me relever, ma vue par défilement ne monte pas. Au lieu de cela, SwipeRefreshLayout reçoit un appel. Que devrais-je faire?

Sil te plait aide moi.

16
rupesh

Je dirais qu'il est préférable d'avoir un SwipeRefreshLayout étendu avec auditeur pour pouvoir ajouter diverses conditions à partir des classes qui affichent cette présentation.

Quelque chose comme ce qui suit: GeneralSwipeRefreshLayout.Java

public class GeneralSwipeRefreshLayout extends SwipeRefreshLayout {   
  private OnChildScrollUpListener mScrollListenerNeeded;

  public interface OnChildScrollUpListener {
    boolean canChildScrollUp();
  }

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

 /**
  * Listener that controls if scrolling up is allowed to child views or not
  */
  public void setOnChildScrollUpListener(OnChildScrollUpListener listener) {
    mScrollListenerNeeded = listener;   
  }

  @Override
  public boolean canChildScrollUp() {
    if (mScrollListenerNeeded == null) {
      Log.e(GeneralSwipeRefreshLayout.class.getSimpleName(), "listener is not defined!");
    }
    return mScrollListenerNeeded != null && mScrollListenerNeeded.canChildScrollUp();
  }
}

Et ensuite, dans votre classe qui affiche SwipeRefreshLayout contenant une disposition ListView ou GridView, vous pouvez faire quelque chose comme ceci:

mSwipeLayout.setOnChildScrollUpListener(new OnChildScrollUpListener() {
  @Override
  public boolean canChildScrollUp() {
    return mListView.getFirstVisiblePosition() > 0 || 
           mListView.getChildAt(0) == null || 
           mListView.getChildAt(0).getTop() < 0;
  }
});
29
goRGon

Créez simplement une classe qui étend SwipeRefreshLayout et override la méthode canChildScrollUp(). Renvoie true lorsque vous souhaitez faire défiler l'écran pour votre contrôle.

Par exemple pour scrollview vous pouvez essayer ceci,

@override.
boolean canChildScrollUp()
{
   //your condition to check scrollview reached at top while scrolling
   if(scrollview.getScrollY() == 0.0)
      return true;
   else
      return false;
}
6
AndyN

Comme d'autres l'ont déjà indiqué, si vous n'avez pas votre vue défilable (c.-à-d. Liste vue) comme enfant direct de SwipeRefreshLayout, le stock canChildScrollUp ne fonctionnera pas.

A voir avec la logique simple que SwipeRefreshLayout utilise pour vérifier la capacité de la vue enfant à défiler.

J'utilisais un ListView dans ActionbarActivity et je voulais inclure une vue vide chaque fois que ma liste était vide. Cela a posé des problèmes car la classe SwipeRefreshLayout ne peut avoir qu'un seul enfant. Notez qu'il vérifie également la capacité de cet enfant à faire défiler jusqu'à déterminer si une liste déroulante provoque le défilement de l'enfant, ou si le contenu de ce dernier est actualisé.

Donc, si vous souhaitez utiliser la même logique que SwipeRefreshLayout, développez simplement la classe et créez une méthode pour vous permettre de transmettre le descripteur à votre vue défilable. Notez que l'implémentation stock utilise canScrollVertically () qui fait exactement ce que nous voulons, mais n'apparaît que dans SDK> = 14.

N'oubliez pas non plus d'inclure le constructeur qui contient le paramètre "AttributeSet" lorsque vous étendez la classe, sinon vous aurez des problèmes pour utiliser la classe dans vos fichiers de présentation.

Ainsi, dans la méthode onCreate de votre activité (dans mon cas, il s'agit d'une ActionBarActivity) qui inclut la vue liste, appelez simplement setMyScrollableView en transmettant votre liste ou la vue que vous utilisez qui défile.

/*Constructor*/
public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}


 View mMyScrollableView = null;  //The content that get's pulled down.
 /*Method used to pass in my scrollable view*/
 public void setMyScrollableView(View view){
    mMyScrollableView = view;
 }

/**
 * @return Whether it is possible for the child view of this layout to
 * scroll up.  This was taken for the most part directly from SwipeRefreshLayout
 */
public boolean canChildScrollUp() {
    if(mMyScrollableView == null)
      return false;
    if (Android.os.Build.VERSION.SDK_INT < 14) {
        if (mMyScrollableView instanceof AbsListView) {
            final AbsListView absListView = (AbsListView) mMyScrollableView;
            return absListView.getChildCount() > 0
        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
        .getTop() < absListView.getPaddingTop());
        } else {
            return mMyScrollableView.getScrollY() > 0;
        }
    } else {
        return ViewCompat.canScrollVertically(mMyScrollableView, -1);
    }
}
5
guyland123

La solution de @ User22791 fonctionne parfaitement et, sur cette base, j'ai créé une bibliothèque disponible sur github que vous pouvez utiliser (et modifier) ​​pour faciliter l'utilisation de swipeRefreshLayout aux développeurs. C'est ici: https://github.com/dagova/referencedSwipeRefreshLayout

En gros, il vous suffit de référencer dans votre mise en page la vue à vérifier dans la méthode canChildScrollUp. J'espère que cela vous sera utile.

3
David Varela

La solution la plus simple consiste à utiliser onScrollListener et à vérifier si l'utilisateur peut voir firstElement.

someView.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView absListView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (isViewAtTop()) {
                swipeLayout.setEnabled(true);
            } else {
                swipeLayout.setEnabled(false);
            }
        }

    }

    @Override
    public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == 0) {
            swipeLayout.setEnabled(true);
        } else {
            swipeLayout.setEnabled(false);
        }
    }
});

Où méthode isViewAtTop () est une autre méthode qui vérifie que cette vue défile jusqu'en haut

2
c0rp

J'ai aussi trouvé que les autres réponses ne fonctionnaient pas tout à fait.

Il m’a fallu un bon bout de temps pour comprendre qu’ils utilisaient la méthode getScrollY() qui, comme l'explique cette réponse }, est une méthode View décrivant la distance parcourue dans un conteneur, et non une méthode décrivant votre conteneur de défilement a été défilé.

Si vous utilisez la même technique que dans les autres réponses (en remplaçant la méthode canChildScrollUp()), vous pouvez facilement vérifier si le point de défilement est à son point le plus élevé:

@Override
public boolean canChildScrollUp() {
    return !isListAtTop();
}

private boolean isListAtTop()   {   
    if(mGridView.getChildCount() == 0) return true;
    return mGridView.getChildAt(0).getTop() == 0;
}

(Comme vous pouvez le voir, j'utilise une GridView, mais vous pouvez aussi utiliser une ListView)

2
Graeme

Ok je le fais travailler. Si le SwipeRefreshLayout est la racine de la présentation et que le ScrollView réside profondément dans la hiérarchie (j'avais placé le ScrollView dans un RelativeLayout) et non l'enfant direct du SwipeRefreshLayout, il ne détectera pas un glissement vers le haut sur le ScrollView correctement.

Vous devez créer une classe personnalisée qui étend SwipeRefreshLayout et remplacer la méthode canChildScrollUp() dans SwipRefreshLayout.

Voici un exemple:

 public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {

    private ScrollView scrollview;

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

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

    public void setView(ScrollView view) {
        this.scrollview = view;
    }

    @Override
    public boolean canChildScrollUp() {
        return scrollview.getScrollY() != 0;
    }

}
1
nitesh goel