Skip to content

Effetto di scorrimento eccessivo simile a quello di iOS su Android

Questo team di scrittura ha dedicato lunghe ore alla ricerca per rispondere alla tua domanda, condividiamo la soluzione con te e il nostro obiettivo è quello di essere di grande supporto per te.

Soluzione:

Ho messo insieme velocemente una semplice soluzione basata su un CoordinatorLayout.Behavior. Non è perfetta, si può forse dedicare un po' di tempo alla sua messa a punto, ma non è male. In ogni caso, il risultato dovrebbe essere simile a questo:

enter image description here

Una piccola nota a margine prima di iniziare con la risposta: Raccomando vivamente di usare l'opzione NestedScrollView della libreria di supporto invece di un normale ScrollView. Sono identici in tutto e per tutto, ma il NestedScrollView implementa il comportamento corretto dello scorrimento annidato sui livelli API inferiori.

Comunque, iniziamo con la mia risposta: La soluzione che ho proposto funzionerebbe con qualsiasi contenitore scorrevole, sia esso un contenitore ScrollView, ListView o RecyclerView e non c'è bisogno di sottoclassi di alcun elemento Views per implementarlo.

Per prima cosa è necessario aggiungere la Design Support Library di Google al progetto, se non la si sta già utilizzando:

compile 'com.android.support:design:25.0.1'

Ricordate che se non state puntando al livello API 25 (cosa che dovreste fare, tra l'altro), allora dovete includere la versione più recente per il vostro livello API (ad esempio, compile 'com.android.support:design:24.2.0' ).compile 'com.android.support:design:24.2.0'per il livello API 24).

Qualunque contenitore scrollabile si stia usando, deve essere avvolto in un elemento CoordinatorLayout nel layout. Nel mio esempio sto usando un elemento NestedScrollView:




    

        

    


Il CoordinatorLayout consente di assegnare un elemento Behavior alle sue viste figlie dirette. In questo caso assegneremo un elemento Behavior alla vista NestedScrollView che implementerà l'effetto di rimbalzo dell'overscroll.

Diamo un'occhiata al codice dell'elemento Behavior:

public class OverScrollBounceBehavior extends CoordinatorLayout.Behavior {

    private int mOverScrollY;

    public OverScrollBounceBehavior() {
    }

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

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        mOverScrollY = 0;
        return true;
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        if (dyUnconsumed == 0) {
            return;
        }

        mOverScrollY -= dyUnconsumed;
        final ViewGroup group = (ViewGroup) target;
        final int count = group.getChildCount();
        for (int i = 0; i < count; i++) {
            final View view = group.getChildAt(i);
            view.setTranslationY(mOverScrollY);
        }
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
        final ViewGroup group = (ViewGroup) target;
        final int count = group.getChildCount();
        for (int i = 0; i < count; i++) {
            final View view = group.getChildAt(i);
            ViewCompat.animate(view).translationY(0).start();
        }
    }
}

Spieghiamo che cosa è un Behavior e come funzionano va oltre lo scopo di questa risposta, quindi mi limiterò a spiegare rapidamente cosa fa il codice qui sopra. Il Behavior intercetta tutti gli eventi di scorrimento che avvengono nei figli diretti dell'elemento CoordinatorLayout. Nella sezione onStartNestedScroll() si restituisce true poiché siamo interessati a qualsiasi evento di scorrimento. In onNestedScroll() guardiamo il metodo dyUnconsumed che ci dice quanta parte dello scorrimento verticale non è stata consumata dal contenitore di scorrimento (in altre parole, l'overscroll) e quindi trasla i figli del contenitore di scorrimento di quella quantità. Poiché stiamo ottenendo solo valori delta, dobbiamo sommarli tutti nel parametro mOverscrollY . onStopNestedScroll() viene richiamato quando l'evento di scorrimento si ferma. Questo è il momento in cui animiamo tutti i figli del contenitore di scorrimento, riportandoli alla loro posizione originale.

Per assegnare la variabile Behavior all'elemento NestedScrollView dobbiamo usare il parametro layout_behavior e passare il nome completo della classe dell'elemento Behavior che vogliamo usare. Nel mio esempio, la classe di cui sopra si trova nel pacchetto com.github.wrdlbrnft.testapp quindi devo impostare com.github.wrdlbrnft.testapp.OverScrollBounceBehavior come valore. layout_behavior è un attributo personalizzato dell'elemento CoordinatorLayout quindi è necessario inserire il prefisso con lo spazio dei nomi corretto:




    

        

    


Si noti lo spazio dei nomi che ho aggiunto all'elemento CoordinatorLayout e al tag app:layout_behavior che ho aggiunto all'elemento NestedScrollView.

E questo è tutto ciò che dovete fare! Sebbene questa risposta si sia rivelata più lunga di quanto intendessi, ho saltato alcune delle nozioni di base, come l'attributo CoordinatorLayout e Behaviors. Quindi, se non avete familiarità con questi o avete altre domande, non esitate a chiedere.

Grazie a Xaver Kapeller, ho scritto la mia soluzione con la sovrascrittura di fling e piccole aggiunte, usando kotlin e androidx

enter image description here

Aggiungere la dipendenza del coordinatore

implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"

Creare una nuova classe che estenda CoordinatorLayout.Behavior

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat

class OverScrollBehavior(context: Context, attributeSet: AttributeSet)
: CoordinatorLayout.Behavior() {

companion object {
    private const val OVER_SCROLL_AREA = 4
}

private var overScrollY = 0

override fun onStartNestedScroll(
    coordinatorLayout: CoordinatorLayout,
    child: View,
    directTargetChild: View,
    target: View,
    axes: Int,
    type: Int
): Boolean {
    overScrollY = 0
    return true
}

override fun onNestedScroll(
    coordinatorLayout: CoordinatorLayout,
    child: View,
    target: View,
    dxConsumed: Int,
    dyConsumed: Int,
    dxUnconsumed: Int,
    dyUnconsumed: Int,
    type: Int,
    consumed: IntArray
) {
    if (dyUnconsumed == 0) {
        return
    }

    overScrollY -= (dyUnconsumed/OVER_SCROLL_AREA)
    val group = target as ViewGroup
    val count = group.childCount
    for (i in 0 until count) {
        val view = group.getChildAt(i)
        view.translationY = overScrollY.toFloat()
    }
}

override fun onStopNestedScroll(
    coordinatorLayout: CoordinatorLayout,
    child: View,
    target: View,
    type: Int
) {
    // Smooth animate to 0 when the user stops scrolling
    moveToDefPosition(target)
}

override fun onNestedPreFling(
    coordinatorLayout: CoordinatorLayout,
    child: View,
    target: View,
    velocityX: Float,
    velocityY: Float
): Boolean {
    // Scroll view by inertia when current position equals to 0
    if (overScrollY == 0) {
        return false
    }
    // Smooth animate to 0 when user fling view
    moveToDefPosition(target)
    return true
}

private fun moveToDefPosition(target: View) {
    val group = target as ViewGroup
    val count = group.childCount
    for (i in 0 until count) {
        val view = group.getChildAt(i)
        ViewCompat.animate(view)
            .translationY(0f)
            .setInterpolator(AccelerateDecelerateInterpolator())
            .start()
    }
}

}

Creare un file XML con CoordinatorLayout e NestedScrollView



    
        
    

E non dimenticare di aggiungere

app:layout_behavior=".OverScrollBehavior" // Or your file name

al markup XML di NestedScrollView

Ecco le recensioni e i punteggi

Ricorda che hai la possibilità di commentare se ti è stato utile.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.