Подтвердить что ты не робот

Скрыть FloatingActionButton на прокрутке RecyclerView

Я хочу скрыть/показать FloatingActionButton при прокрутке RecyclerView.

XML:

<android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerview_eventlist"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/fab_createevent"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/fab_margin"
                app:layout_anchor="@id/recyclerview_eventlist"
                app:layout_anchorGravity="bottom|right|end"
                app:layout_behavior="com.eventizon.behavior.ScrollAwareFABBehavior"
                android:src="@drawable/ic_edit"
                app:backgroundTint="@color/custom_color_1"
                app:borderWidth="0dp" />
        </android.support.design.widget.CoordinatorLayout>

DrawerLayout - это родительский макет этого макета.

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {


private static final String TAG = "ScrollAwareFABBehavior";

public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
    super();
    Log.e(TAG,"ScrollAwareFABBehavior");
}

@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout,
        FloatingActionButton child, View target, int dxConsumed,
        int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
    // TODO Auto-generated method stub
    super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
            dxUnconsumed, dyUnconsumed);
    Log.e(TAG,"onNestedScroll called");
    if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
        Log.e(TAG,"child.hide()");
        child.hide();
    } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
        Log.e(TAG,"child.show()");
        child.show();
    }
}

}

Используется это поведение макета для FloatingActionButton. Когда я вижу logcat, вызывает вызов только конструктор. onNestedScroll() не вызывается при прокрутке списка.

4b9b3361

Ответ 1

Хорошо, вот что вам нужно:

Во-первых, поскольку ваш FAB зависит от RecyclerView, добавьте следующее в свой класс поведения:

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
    if(dependency instanceof RecyclerView)
        return true;

    return false;
}

Далее, чтобы получать вызовы onNestedScroll(), вам необходимо переопределить это:

 public boolean onStartNestedScroll(CoordinatorLayout parent, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {

    //predict whether you will need to react to the RecyclerView scroll;
    //if yes, return true, otherwise return false to avoid future calls
    //of onNestedScroll()
    return true;
}

Удачи!

Обновление

Вот что должно выглядеть ваше ScrollAwareFABBehavior:

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
    private static final String TAG = "ScrollAwareFABBehavior";

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

    public boolean onStartNestedScroll(CoordinatorLayout parent, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        return true;
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
        if(dependency instanceof RecyclerView)
            return true;

        return false;
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout,
                               FloatingActionButton child, View target, int dxConsumed,
                               int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        // TODO Auto-generated method stub
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed);

        if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {    
            child.hide();
        } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
            child.show();
        }
    }
}

Кроме того, он был протестирован с помощью com.android.support:design:23.0.1

Ответ 2

Самое простое решение:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy)
    {
        if (dy > 0 ||dy<0 && fab.isShown())
        {
            fab.hide();
        }
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState)
    {
        if (newState == RecyclerView.SCROLL_STATE_IDLE)
        {
            fab.show();
        }

        super.onScrollStateChanged(recyclerView, newState);
    }
});

Ответ 3

Это должно сработать для вас:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx,int dy){
        super.onScrolled(recyclerView, dx, dy);

        if (dy >0) {
            // Scroll Down
            if (fab.isShown()) {
                fab.hide();
            }
        }
        else if (dy <0) {
            // Scroll Up
            if (!fab.isShown()) {
                fab.show();
            }
        }
     }
});

Ответ 4

Так я и сделал. Меня устраивает! Если вы не знаете, как реализовать, вы можете увидеть подробности в этой ссылке https://guides.codepath.com/android/floating-action-buttons

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

    public ScrollAwareFABBehavior(Context context, AttributeSet attributeSet){
        super();
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
            child.hide();
        } else if (dyConsumed < 0 && child.getVisibility() == View.GONE) {
            child.show();
        }
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }
}

Ответ 5

Решение находится в: F.A.B скрывает, но не показывает

Проблема заключается в том, что Android 25.0.x + устанавливает представление в GONE, и поэтому слушатель не сообщает об изменениях.

Ответ 6

Я создал настраиваемый RecyclerView, у которого есть OnUpDownScrollListener, OnLeftRightScrollListener:

Код:

MBRecyclerView.java

public class MBRecyclerView extends RecyclerView {

    private OnScrollListener wrappedUpDownScrollListener;
    private OnScrollListener wrappedLeftRightScrollListener;

    public MBRecyclerView(Context context) {
        super(context);
        init();
    }

    public MBRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MBRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
    }

    // region Scrolling Listener for Up, Down, Left and Right
    public void setOnUpDownScrollListener(final OnUpDownScrollListener onUpDownScrollListener) {
        if (wrappedUpDownScrollListener == null) {
            wrappedUpDownScrollListener = getWrappedUpDownScrollListener(onUpDownScrollListener);
            addOnScrollListener(wrappedUpDownScrollListener);
        }
    }

    public void removeOnUpDownScrollListener() {
        if (wrappedUpDownScrollListener != null) {
            removeOnScrollListener(wrappedUpDownScrollListener);
            wrappedUpDownScrollListener = null;
        }
    }

    public void setLeftOnRightScrollListener(final OnLeftRightScrollListener onLeftRightScrollListener) {
        if (wrappedLeftRightScrollListener == null) {
            wrappedLeftRightScrollListener = getWrappedLeftRightScrollListener(onLeftRightScrollListener);
            addOnScrollListener(wrappedLeftRightScrollListener);
        }
    }

    public void removeOnLeftRightScrollListener() {
        if (wrappedLeftRightScrollListener != null) {
            removeOnScrollListener(wrappedLeftRightScrollListener);
            wrappedLeftRightScrollListener = null;
        }
    }

    private OnScrollListener getWrappedUpDownScrollListener(final OnUpDownScrollListener onUpDownScrollListener) {
        return new OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (onUpDownScrollListener != null) {
                    // Negative to check scrolling up, positive to check scrolling down
                    if (!recyclerView.canScrollVertically(-1)) {
                        onUpDownScrollListener.onScrolledToTop();
                    } else if (!recyclerView.canScrollVertically(1)) {
                        onUpDownScrollListener.onScrolledToBottom();
                    }
                    if (dy > 0) {
                        onUpDownScrollListener.onScrollDown(dy);
                    } else if (dy < 0) {
                        onUpDownScrollListener.onScrollUp(dy);
                    }
                }
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    if (onUpDownScrollListener != null) {
                        onUpDownScrollListener.onScrollStopped();
                    }
                }
            }
        };
    }

    private OnScrollListener getWrappedLeftRightScrollListener(final OnLeftRightScrollListener onLeftRightScrollListener) {
        return new OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (onLeftRightScrollListener != null) {
                    // Negative to check scrolling left, positive to check scrolling right
                    if (!recyclerView.canScrollHorizontally(-1)) {
                        onLeftRightScrollListener.onScrolledToMostLeft();
                    } else if (!recyclerView.canScrollVertically(1)) {
                        onLeftRightScrollListener.onScrolledToMostRight();
                    }
                    if (dy > 0) {
                        onLeftRightScrollListener.onScrollRight(dx);
                    } else if (dy < 0) {
                        onLeftRightScrollListener.onScrollLeft(dx);
                    }
                }
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    if (onLeftRightScrollListener != null) {
                        onLeftRightScrollListener.onScrollStopped();
                    }
                }
            }
        };
    }

    public abstract class OnUpDownScrollListener {
        public void onScrollUp(int dy) {}

        public void onScrollDown(int dy) {}

        public void onScrolledToTop() {}

        public void onScrolledToBottom() {}

        public void onScrollStopped() {}
    }

    public abstract class OnLeftRightScrollListener {
        public void onScrollLeft(int dx) {}

        public void onScrollRight(int dx) {}

        public void onScrolledToMostRight() {}

        public void onScrolledToMostLeft() {}

        public void onScrollStopped() {}
    }
    // endregion
}

Использование (UpDownScrollListener):

    mbRecyclerView.setOnUpDownScrollListener(new MBRecyclerView.OnUpDownScrollListener() {
        @Override
        public void onScrollUp(int dy) {
            // show
        }

        @Override
        public void onScrollDown(int dy) {
            // hide
        }

        // aditional functions:
        public void onScrolledToTop() {}
        public void onScrolledToBottom() {}
        public void onScrollStopped() {}
    });

Аналогично, вы можете обрабатывать прокрутку LeftRight, установив

setOnLeftRightScrollListener

Надеюсь, это может помочь кому-то:)

Ответ 7

//lv = ListView

    lv.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            fab.setVisibility(view.getFirstVisiblePosition() == 0 ? View.VISIBLE : View.INVISIBLE);
        }
    });

Ответ 8

Попробуйте это

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                //Customize your if statement  
                if (recyclerView.computeVerticalScrollOffset() > recyclerView.getHeight() * 2) {
                    if (!fab.isShown()) {
                        fab.show();
                    }
                } else {
                    fab.hide();
                }
            }
        });

пользоваться.

Ответ 9

Я использовал это в методе RecyclerView.Adapter onBindViewHolder, чтобы установить нижнее поле последнего элемента в списке на 72dp, чтобы оно прокручивалось над кнопкой плавающего действия.

Это не требует фиктивной записи в списке.

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    // other binding code goes here.

    if (position + 1 == getItemCount()) {
        // set bottom margin to 72dp.
        setBottomMargin(holder.itemView, (int) (72 * Resources.getSystem().getDisplayMetrics().density));
    } else {
        // reset bottom margin back to zero. (your value may be different)
        setBottomMargin(holder.itemView, 0);
    }
}

public static void setBottomMargin(View view, int bottomMargin) {
    if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
        view.requestLayout();
    }
}