Как обнаружить вложенные броски, остановленные в CoordinatorLayout.Behavior?

Как определить, прекратились ли вложенные броски целиком с помощью CoordinatorLayout.Behavior? Нет такого API, который может дать мне обратный вызов, когда полностью перестанет работать просмотрщик.

2 ответа

Я начал спускаться по этой кроличьей норе, пытаясь скрыть кнопку с плавающим действием (FAB) во время прокрутки RecyclerView. Правильный способ сделать это в соответствии с несколькими источниками - это расширить FloatingActionButton.Behavior, переопределить onStartNestedScroll а также onStopNestedScroll методы и привязать ваше поведение к FAB, например app:layout_behavior="com.justingarrick.ui.ScrollAwareFabBehavior", Это работает для обычных (медленных) событий прокрутки, но onStopNestedScroll не вызывается, когда бросок заканчивается.

В настоящее время, по-видимому, существует ряд открытых вопросов, связанных с переключением режимов прокрутки и прокрутки; Обходной путь для меня заключался в реализации OnScrollListener для моего RecyclerView и просто изменить состояние FAB программно, например

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;
    }
}

ОБНОВЛЕНИЕ: это работает правильно в 99% случаев, но если вы используете show() а также hide() методы из версии 22.2.1 библиотеки проектирования, вы столкнетесь с проблемами при попытке прокрутить вверх в верхней части вашего RecyclerView или вниз в нижней части вашего RecyclerView, потому что представление рециркулятора переключает состояния с RecyclerView.SCROLL_STATE_DRAGGING в RecyclerView.SCROLL_STATE_IDLE так быстро, что это создает условия гонки в FloatingActionButtonHoneycombMr1#show(), Итак, чтобы исправить это (вздох), вам нужно либо переключиться на setVisibility() звонки, если вы не заботитесь об анимации или повторно реализуете анимацию без условия гонки, например

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);
         }
     });
 }

Я использую ScrollerCompat с методом ScrollerCompat.fling(..) для обработки промежуточных состояний прокрутки. Так что я знаю, когда прокрутка заканчивается.

@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;
         }
     }
 }
Другие вопросы по тегам