Скрыть 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()
не вызывается при прокрутке списка.
Ответы
Ответ 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();
}
}