5

Chcę zaimplementować efekt przeskoku bitu w stylu iOS w mojej aplikacji.Efekt przewijania w systemie iOS na Androidzie

Natknąłem się na to link, co sugeruje utworzenie niestandardowego ScrollView. Problem polega jednak na tym, że gdy przewijam szybko i szybko, to działa dobrze, ale jak tylko przeciągnę dolną lub górną część ekranu, to po prostu utknęło i efekt już nie działa.

Jako przykład tego rodzaju animacji chcę osiągnąć można spojrzeć na to:

Jest to kod Obecnie mam:

public class ObservableScrollView extends ScrollView 
{ 
    private static final int MAX_Y_OVERSCROLL_DISTANCE = 150; 

    private Context mContext; 
    private int mMaxYOverscrollDistance; 

    public ObservableScrollView(Context context) 
    { 
     super(context); 
     mContext = context; 
     initBounceScrollView(); 
    } 

    public ObservableScrollView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
     mContext = context; 
     initBounceScrollView(); 
    } 

    public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
     mContext = context; 
     initBounceScrollView(); 
    } 

    private void initBounceScrollView() 
    { 
     //get the density of the screen and do some maths with it on the max overscroll distance 
     //variable so that you get similar behaviors no matter what the screen size 

     final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 
     final float density = metrics.density; 

     mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE); 
    } 

    @Override 
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) 
    { 
     //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverscrollDistance; 
     return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent); 
    } 
} 

Odpowiedz

13

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:

enter image description here

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ć.

+0

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

+0

@Star Nie rozumiem, co mówisz. Moja odpowiedź zawiera już rozwiązanie, które replikuje gif w twojej odpowiedzi. Czego jeszcze chcesz? –

+0

@ Cień na pewno. Wszystko, czego potrzebujesz, to ta sama matematyka, aby zablokować przewijanie w sposób wykładniczy. –

0

użyć tej

Private ScrollView scrMain; 

scrMain = (ScrollView) v.findViewbyId(R.id.scrMain); 

OverScrollDecorHandler.setScrollView(scrMain);