Scorrere verso l’alto non funziona con SwipeRefreshLayout nella Listview

Voglio implementare scorrere la funzionalità di aggiornamento con una listView. Ci sono anche altri elementi della vista nello stesso layout del file che vengono visualizzati, se l’elenco è vuoto. Ecco il mio file di layout. Il problema è che quando ho scorrere verso il basso e quindi si tenta di scorrere verso l’alto, invece di scorrimento a tutti la strada verso l’alto e poi rinfrescante, appena rinfresca c’e scorrere verso l’alto non funziona.

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

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

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="64dp"
        android:paddingLeft="16dp"
        android:paddingRight="16dp" >

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:src="@drawable/inbox_empty" />

        <TextView
            android:id="@+id/noEventsText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="16dp"
            android:layout_toRightOf="@+id/noEventsIcon" />

        <View
            android:id="@+id/divider"
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="@color/dividerOnBlack" />
    </RelativeLayout>

    <ListView
        android:id="@+id/list_items"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="@android:color/transparent"
        android:choiceMode="multipleChoice"
        android:descendantFocusability="afterDescendants"
        android:divider="@android:color/transparent"
        android:dividerHeight="0px"
        android:scrollbars="none" />
</LinearLayout>

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

Questo è il mio onScroll metodo.

@Override
public void onScroll(AbsListView view,int firstVisibleItem,int visibleItemCount,int totalItemCount) {
    //If the total item count is zero and the previous isn't, assume the
    //list is invalidated and should be reset back to initial state
    if (totalItemCount < previousTotalItemCount) {
        this.currentPage = this.startingPageIndex;
        this.previousTotalItemCount = totalItemCount;
        if (totalItemCount == 0) { this.loading = true; } 
    }

    //If it's still loading, we check to see if the dataset count has
    //changed, if so we conclude it has finished loading and update the current page
    //number and total item count.
    if (loading && (totalItemCount > previousTotalItemCount)) {
        loading = false;
        previousTotalItemCount = totalItemCount;
        currentPage++;
    }

    //If reverse then the firstVisibleItem is calculated wrong
    if (reverse) {
        firstVisibleItem = totalItemCount - firstVisibleItem;
    }
    //If it isn't currently loading, we check to see if we have breached
    //the visibleThreshold and need to reload more data.
    //If we do need to reload some more data, we execute onLoadMore to fetch the data.
    if (!loading && (totalItemCount - visibleItemCount)<=(firstVisibleItem + visibleThreshold)) {
        onLoadMore(currentPage + 1, totalItemCount);
        loading = true;
    }
}
InformationsquelleAutor user3773337 | 2014-08-12



9 Replies
  1. 53

    In ordine per SwipeRefreshLayout per funzionare, ha bisogno di essere la controllante diretta della tua ListView, e il controllo ListView deve essere attivo prima vista figlio del SwipeRefreshLayout.

    La documentazione per SwipeRefreshLayout dice che la ListView dovrebbe essere solo un bambino, ma è bene se si dispone di più di un bambino, come lungo come la ListView è il primo. Questo significa, per esempio, che SwipeRefreshLayout funzionerà correttamente se si utilizza un adattatore con una vista per il “vuoto”. Per esempio:

    <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/swipe_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".NearbyJobsActivity$PlaceholderFragment">
    
        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@color/list_divider"
            android:dividerHeight="1dp"
            android:listSelector="@drawable/list_row_selector" />
    
        <TextView
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center" />
    
    </android.support.v4.widget.SwipeRefreshLayout>

    Se è possibile gestire questo tipo di layout, quindi SwipeRefreshLayout funziona bene e non avrete bisogno di alcuna delle soluzioni elencate in altre risposte.

    Mio problema era che mi stava caricando la mia ListView come un Frammento, così ho effettivamente avuto:

    <SwipeRefreshLayout>
    
        <FrameLayout>           )
             <ListView/>        \ fragment
             <TextView/>        /
        </FrameLayout>          )
    
    </SwipeRefreshLayout>

    In modo che il SwipeRefreshLayout stata la scelta del FrameLayout come “target” e la sua di default canChildScrollUp() attuazione restituisce sempre false. Una volta ho spostato il SwipeRefreshLayout all’interno del Frammento, tutto ha iniziato a lavorare correttamente.

    <FrameLayout>
    
        <SwipeRefreshLayout>    )
             <ListView/>        \ fragment
             <TextView/>        /
        </SwipeRefreshLayout>   )
    
    </FrameLayout>
  2. 33

    Ho avuto lo stesso problema e risolto:

    listView = (ListView) findViewById(R.id.listView);
    listView.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
         public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (listView.getChildAt(0) != null) {
            swipeRefreshLayout.setEnabled(listView.getFirstVisiblePosition() == 0 && listView.getChildAt(0).getTop() == 0);
            }
        }
    });
    • Buona soluzione !
    • questa soluzione è la migliore di sempre. molto semplice snippet
    • Grazie Unico che ha funzionato dal momento che utilizza di Default la Lista dovuto trovare cercando android.R.id.list
    • Dovrebbe essere accettato risposta!!! Grazie per la soluzione.
    • Grande Uomo che ha risolto il mio problema con Gridview grazie mille cara
  3. 28

    Creare un layout come questo.

    <android.support.v4.widget.SwipeRefreshLayout  
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/guides_no_results"
            android:id="@+id/empty_view"
            android:gravity="center"
            android:padding="16dp"
            android:fontFamily="sans-serif-light"
            android:textSize="20sp"
            android:visibility="gone"/>
    
    
        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:drawSelectorOnTop="true"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp"
            android:id="@+id/guides_list" />
    
    </LinearLayout>

    Se si utilizza questo come è, ogni volta che si scorre fino in tale prospettiva, il SwipeRefreshLayout incendi e aggiornamenti, fare la tua applicazione in grado di scorrere verso l’alto in un elenco.

    Qui il trucco è quello di legare il OnScrollListener dalla ListView manualmente. Verificare se la prima riga viene visualizzato corrisponde alla prima posizione più in alto, e quindi attivare il SwipeRefreshLayout. In caso contrario, è possibile disattivarlo.

    guidesList.setOnScrollListener(new AbsListView.OnScrollListener()
    {  
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState)
        {
    
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
        {
            int topRowVerticalPosition = (guidesList == null || guidesList.getChildCount() == 0) ? 0 : guidesList.getChildAt(0).getTop();
            swipeContainer.setEnabled(firstVisibleItem == 0 && topRowVerticalPosition >= 0);
        }
    });

    Con questo piccolo snippet ora funziona perfettamente.

    Codifica felice!

    Fonte – http://nlopez.io/swiperefreshlayout-with-listview-done-right/

    • Mentre questo link può rispondere alla domanda, è meglio includere le parti essenziali di qui la risposta e fornire il link di riferimento. Link-solo le risposte possono essere inutili se la pagina collegata modifiche.
    • la bandiera è stata per il post originale con i link solo rispondere, che è stato risolto nel frattempo.
    • Bene, così siamo in grado di eliminare i commenti inutili 😉
    • Funziona, ma ho un problema diverso in questo. Quando la prima riga della lista sono la dimensione maggiore del genitore (per dire la sua un testo con il testo molto lungo) quindi non visualizzare più di qualsiasi altra riga.
    • Questo funziona per me, ma non è l’ideale che necessitano di un riferimento al Activity‘s SwipeRefreshLayout se sei attuazione del presente in un frammento.
  4. 10

    Fare il vostro proprio implementazione di SwipeRefreshLayout e ignorare il canChildScrollUp in questo modo:

    @Override
    public boolean canChildScrollUp() {
    if (scrollView != null)
        return scrollView.canScrollVertically(-1);
    
    return false;
    }

    basta sostituire con qualsiasi sottoclasse della ScrollView.

  5. 5

    Ho avuto un problema simile in cui il bambino del mio SwipeRefreshLayout era un FrameLayout che aveva un TextView e ListView come i bambini e quando ho scorrere fino al ListView che vorrei provare a fare un aggiornamento.

    Ho risolto utilizzando un custom FrameLayoutche sostituisce il canScrollVertically() metodo

    pacchetto com.wi.direttore.interfaccia utente.comune;

    import android.content.Context;
    import android.util.AttributeSet;
    import android.widget.FrameLayout;
    
    /**
     * Created by devansh on 9/22/15.
     */
    public class FrameLayoutForSwipeRefresh extends FrameLayout {
    
        public FrameLayoutForSwipeRefresh(Context context) {
            super(context);
        }
    
        public FrameLayoutForSwipeRefresh(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public FrameLayoutForSwipeRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public boolean canScrollVertically(int direction) {
            if (super.canScrollVertically(direction)) {
                return true;
            }
    
            int cc = getChildCount();
            for (int i = 0; i < cc; i++) {
                if (getChildAt(i).canScrollVertically(direction)) {
                    return true;
                }
            }
    
            return false;
        }
    }
    • Ho dovuto cambiare il mio frammento di layout leggermente per abbinare il vostro (il bene, senza la TextView) per questo lavoro, ma funziona a meraviglia. Una bella, pulita soluzione, grazie! 🙂
  6. 3

    Ancora più semplice, basta impostare SwipeRefreshLayout abilitato se firstVisibleItem o disattivato se non:

    yourList.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override 
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            yourSwipeRefreshLayout.setEnabled(firstVisibleItem == 0);
        }
    });
  7. 0

    Mio Gridview Iniziare a Lavorare con Swipefreshlayout

    gridView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
    
            public void onScrollStateChanged(AbsListView view, int scrollState)
    
            {
    
            }
    
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (gridView.getChildAt(0) != null) {
                    mrefreshlayout.setEnabled(gridView.getFirstVisiblePosition() == 0 && gridView.getChildAt(0).getTop() == 0);
                }
    
             }
    
    
           });

    layout in xml

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swiperefreshlayout"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    
        <LinearLayout
            android:background="#ffffff"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <GridView
                android:background="#ffffff"
                android:gravity="center"
                android:verticalSpacing="2dp"
                android:horizontalSpacing="2dp"
                android:numColumns="2"
                android:id="@+id/grid_view"
                android:animateLayoutChanges="true"
                android:overScrollMode="always"
                android:scrollbars="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
    
            <TextView
                android:id="@+id/nofieldtv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_above="@+id/adlayout"
                android:textColor="#000000"
                android:gravity="center"
                android:visibility="gone"
                android:textSize="16sp"
                android:layout_below="@+id/headerLayout"
                android:layout_marginTop="2dp">
    
            </TextView>
    
        </LinearLayout>
    
    
    </android.support.v4.widget.SwipeRefreshLayout>
  8. 0

    In pratica, vogliamo scorrere qualcosa di scorrevole. Siamo in grado di mettere tutti i punti di vista in ScrollView.

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
    
            </LinearLayout>
        </ScrollView>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

    Ma lo scorrimento ListView può richiedere alcune modifiche – wrap_content ListView

  9. 0

    Per Xamarin ho avuto lo stesso problema (Scorrere verso l’alto non funziona con SwipeRefreshLayout nella Listview) e implementato in questo modo.

    public void OnScroll(AbsListView vista, int firstVisibleItem, int visibleItemCount, int totalItemCount)
    {

        }
    
        public void OnScrollStateChanged(AbsListView view, [GeneratedEnum] ScrollState scrollState)
        {
            if(listView.GetChildAt(0) != null)
            {
                swipeRefreshLayout.Enabled=listView.FirstVisiblePosition==0 && listView.GetChildAt(0).Top==0;
            }
        }

Lascia un commento