I szybko umieścić razem proste rozwiązanie oparte na CoordinatorLayout.Behavior
. Nie jest doskonały, możesz spędzić trochę czasu, aby go trochę poprawić, ale nie jest zły. W każdym razie wynik powinien wyglądać mniej więcej tak:
Jako mały marginesie zanim zacznę z odpowiedzią: Gorąco polecam skorzystanie z NestedScrollView
z biblioteki wsparcia zamiast normalnego ScrollView
. Są identyczne w jakikolwiek sposób, ale NestedScrollView
implementuje prawidłowe zagnieżdżone zachowanie przewijania na niższych poziomach interfejsu API.
Zresztą zacznijmy moją odpowiedź: Rozwiązanie wymyśliłem będzie działać z każdą funkcją przewijania kontenera, czy to ScrollView
, ListView
lub RecyclerView
i nie trzeba do podklasy żadnego Views
do jej wykonania.
Najpierw trzeba dodać Biblioteka Projekt Wsparcia Google do swojego projektu, jeśli nie korzysta już go:
compile 'com.android.support:design:25.0.1'
Pamiętaj, że jeśli nie są kierowane poziom API 25 (które powinny w drodze) musisz dołączyć najnowszą wersję dla swojego poziomu API (np. compile 'com.android.support:design:24.2.0'
dla poziomu API 24).
Niezależnie od tego, który kontener przewijalnie jest używany, należy zawinąć w szablonie w postaci CoordinatorLayout
. W moim przykładzie używam NestedScrollView
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- content -->
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
CoordinatorLayout
pozwala przypisać Behavior
do swoich bezpośrednich widoków podrzędnych. W tym przypadku przypiszemy Behavior
do NestedScrollView
, który będzie realizował efekt odskoku przerzucania.
Miejmy tylko spojrzeć na kodzie Behavior
:
public class OverScrollBounceBehavior extends CoordinatorLayout.Behavior<View> {
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();
}
}
}
Wyjaśniając co Behavior
i jak one działają wykracza poza zakres tej odpowiedzi, więc jestem po prostu się szybko wyjaśnić, co powyżej kod robi. Behavior
przechwytuje wszystkie zdarzenia przewijania, które zdarzają się bezpośrednio dzieciom CoordinatorLayout
. W metodzie onStartNestedScroll()
zwracamy true
, ponieważ jesteśmy zainteresowani wszelkimi zdarzeniami przewijania.W wersji onNestedScroll()
przyjrzymy się parametrowi dyUnconsumed
, który mówi nam, ile przewijania w pionie nie zostało zużyte przez przewijany kontener (innymi słowy przewyższenie), a następnie przetłumacz dzieci przewijającego kontenera o tę wartość. Ponieważ właśnie otrzymujemy wartości delta, musimy je wszystkie podsumować w zmiennej mOverscrollY
. onStopNestedScroll()
jest wywoływana, gdy zdarzenie przewijania się zatrzymuje. To jest, gdy animujemy wszystkie dzieci przewijanego pojemnika z powrotem do ich pierwotnej pozycji.
Aby przypisać Behavior
do NestedScrollView
musimy użyć atrybutu xml layout_behavior
i przechodzą w pełnej nazwy klasowej Behavior
chcemy użyć. W moim przykładzie powyższa klasa znajduje się w pakiecie com.github.wrdlbrnft.testapp
, więc muszę ustawić com.github.wrdlbrnft.testapp.OverScrollBounceBehavior
jako wartość. layout_behavior
jest atrybutem zwyczaju CoordinatorLayout
więc musimy poprzedzić je prawidłowego nazw:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.github.wrdlbrnft.testapp.OverScrollBounceBehavior">
<!-- content -->
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Wskazówka przestrzeń nazw dodałem na CoordinatorLayout
i atrybut app:layout_behavior
dodałem na NestedScrollView
.
I to wszystko, co musisz zrobić! Podczas gdy ta odpowiedź okazała się dłuższa niż zamierzałem, pominąłem niektóre podstawy dotyczące CoordinatorLayout
i Behaviors
. Więc jeśli nie jesteś zaznajomiony z tymi lub masz inne pytania, nie wahaj się zapytać.
Hi @Xaver Kapler dzięki za aktualizację. I jeszcze jedna wątpliwość polega na tym, że ręcznie wycofujemy się i podskakujemy. Ale w załączonym ekranie gif, jeśli przewijamy i kiedy osiągnie dno, to odbija się. To samo na górze również.i sprawdzane przez pobranie aplikacji. Jak można to osiągnąć w trybie przewijania? – Star
@Star Nie rozumiem, co mówisz. Moja odpowiedź zawiera już rozwiązanie, które replikuje gif w twojej odpowiedzi. Czego jeszcze chcesz? –
@ Cień na pewno. Wszystko, czego potrzebujesz, to ta sama matematyka, aby zablokować przewijanie w sposób wykładniczy. –