5

Jak wykryć, czy zagnieżdżanie w gnieździe zostało całkowicie zatrzymane za pomocą CoordinatorLayout.Behavior? Nie ma takiego api, który może dać mi oddzwonić, gdy przeglądarka recykling rzuca całkowicie zatrzymuje.Jak wykryć zagnieżdżanie zagnieżdżane zatrzymane w CoordinatorLayout.Behavior?

+0

Nie możesz osiągnąć tego samego z 'SCROLL_STATE_IDLE'? –

+0

Nie ma metody, jak onScrollStateChanged (widok AbsListView, int scrollState) w CoordinatorLayout. Zbawienie, które może dać mi scrollState. Istnieje jedna metoda o nazwie onStopNestedScroll, ale jest ona wywoływana przed całkowitym zatrzymaniem się listy. – shekar

+0

Mam na myśli 'onScrollChanged()' dla 'RecyclerView' –

Odpowiedz

6

Zacząłem tę króliczą dziurę, próbując ukryć Floating Action Button (FAB) podczas przewijania RecyclerView. Odpowiednim sposobem uzyskania tego zgodnie z wieloma numerami jest rozszerzenie , nadpisanie metod onStartNestedScroll i onStopNestedScroll i połączenie z zachowaniem do FAB, np. app:layout_behavior="com.justingarrick.ui.ScrollAwareFabBehavior". Działa to w przypadku normalnych (powolnych) zdarzeń przewijania, ale onStopNestedScroll nie jest wywoływane, gdy kończy się rzut.

Obecnie wydaje się, że istnieje wiele otwartych issues z zachowaniem rzucania i przewijania; obejściem było dla mnie wdrożenie OnScrollListener dla mojego RecyclerView i po prostu zmiana stanu FAB programowo, np.

public class MyFragment extends Fragment { 

    @Bind(R.id.account_list) RecyclerView recyclerView; 
    @Bind(R.id.button_fab) FloatingActionButton fab; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.fragment_accounts, container, false); 
     ButterKnife.bind(this, view); 

     recyclerView.setLayoutManager(layoutManager); 
     recyclerView.setAdapter(adapter); 
     recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 
      @Override 
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 
       super.onScrollStateChanged(recyclerView, newState); 
       if (newState == RecyclerView.SCROLL_STATE_DRAGGING) 
        fab.hide(); // or hideFab(), see below 
       else if (newState == RecyclerView.SCROLL_STATE_IDLE) 
        fab.show(); // or showFab(), see below 
      } 
     }); 

     return view; 
    } 
} 

UPDATE: To działa poprawnie 99% czasu, ale jeśli używasz show() i hide() metody z wersji 22.2.1 biblioteki projektowania, będziesz napotkasz problemy podczas próby przewijać w górnej części okna RecyclerView lub w dół na dole okna RecyclerView, ponieważ widok recyklera przełącza stany z RecyclerView.SCROLL_STATE_DRAGGING na RecyclerView.SCROLL_STATE_IDLE tak szybko, że tworzy warunki wyścigu w FloatingActionButtonHoneycombMr1#show(). Aby to naprawić (westchnienie), musisz przełączyć się na wywołania setVisibility(), jeśli nie interesują Cię animacje lub ponownie zaimplementować animacje bez warunków wyścigu, np.

private void hideFab() { 
    fab.animate().scaleX(0.0F).scaleY(0.0F).alpha(0.0F).setDuration(200L).setInterpolator(new FastOutSlowInInterpolator()).setListener(new AnimatorListenerAdapter() { 
     @Override 
     public void onAnimationEnd(Animator animation) { 
      fab.setVisibility(View.GONE); 
     } 
    }); 
} 

private void showFab() { 
    fab.animate().scaleX(1.0F).scaleY(1.0F).alpha(1.0F).setDuration(200L).setInterpolator(new FastOutSlowInInterpolator()).setListener(new AnimatorListenerAdapter() { 
     @Override 
     public void onAnimationStart(Animator animation) { 
      fab.setVisibility(View.VISIBLE); 
     } 
    }); 
} 
+0

Dzięki za odpowiedź, przynajmniej nie jestem sam, który stanął w obliczu tego problemu. – shekar

+0

Brillant proste rozwiązanie! Musiałem pokazać FAB tylko wtedy, gdy widoczny był określony widok w widoku przewijania i ukryłem go, gdy ten widok był poza ekranem. Dzięki Behavior nie można było zarządzać flingami ... Dzięki słuchaczowi Scroll działa idealnie! –

0

Używam ScrollerCompat z metodą ScrollerCompat.fling (..) do obsługi stanów pośrednich przewijania. Więc wiem, kiedy przewijanie się kończy.

@Override 
public boolean onNestedFling(final CoordinatorLayout coordinatorLayout, final AppBarLayout child, final View target, final float velocityX, final float velocityY, final boolean consumed) { 
    final int scrollY = target.getScrollY(); 
    final double distance = mFlingHelper.getSplineFlingDistance(velocityY); 

    fling(
      child, 
      (int) distance + scrollY, 
      velocityY, 
      scrollY); 

    return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); 
} 

private void fling(final View pChild, final int pMaxOffset, final float pVelocityY, final int pStartY) { 
    stopFling(pChild); 
    mIsFlingRunning = true; 

    if (mScroller == null) { 
     mScroller = ScrollerCompat.create(mContext); 
    } 

    mScroller.fling(
     0, pStartY, // current 
     0, Math.round(pVelocityY), // velocity. 
     0, 0, // x 
     0, pMaxOffset); // y 

    if (mScroller.computeScrollOffset()) { 
     mFlingRunnable = new FlingRunnable(pChild); 
     ViewCompat.postOnAnimation(pChild, mFlingRunnable); 
    } 

} 

private void stopFling(final View pChild) { 
    if (mFlingRunnable != null) { 
     pChild.removeCallbacks(mFlingRunnable); 
     mFlingRunnable = null; 
    } 
} 




private class FlingRunnable implements Runnable { 

    private final View mView; 

    FlingRunnable(final View pView) { 
     mView = pView; 
    } 

    @Override 
    public void run() { 
     if (mView != null && mScroller != null) { 
      if (mScroller.computeScrollOffset()) { 
       mIsFlingRunning = true; 
       // Post ourselves so that we run on the next animation 
       ViewCompat.postOnAnimation(mAppBarLayout, this); 
      } 
     } else { 
      mIsFlingRunning = false; 
     } 
    } 
}