簡體   English   中英

FloatingActionButton 隱藏在列表滾動中

[英]FloatingActionButton hide on list scroll

我正在使用android.support.design.widget package 中的FloatingActionButton

<android.support.design.widget.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentEnd="true"
    android:layout_marginBottom="20dp"
    android:layout_marginEnd="16dp"
    android:clickable="true"
    android:backgroundTint="@color/primaryColor"
    android:src="@drawable/ic_search_white_24dp"
    app:borderWidth="0dp"
    app:elevation="6dp"
    app:backgroundTint="@color/primaryColorDark"
    app:rippleColor="@color/accentColor" />

是否可以將該按鈕配置為在列表視圖向下滾動時使用 animation 隱藏並在列表視圖向上滾動到頂部時再次顯示?

那些希望使用 recyclerview 實現它的人可以這樣做:

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

對不起! 我遲到了幾年才能回答這個問題。 我希望這仍然可以幫助某人。 這也是我的第一個回答。

伙伴們! 無需實現滾動偵聽器。

將以下內容添加到浮動操作按鈕 xml 中:

app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"

給予:

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
        android:id="@+id/fabAddOItransferIn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:text="@string/btn_text_transfer_in"
        app:icon="@android:drawable/ic_input_add"
        app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

為了回應我的以下評論,“對不起!我剛剛注意到這有一個奇怪的副作用。如果添加了 app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior,任何小吃店都會與這個浮動操作按鈕重疊。 ☹️ 取消這條線將防止重疊,浮動操作按鈕將按照它在協調器布局內的預期行為。

為了解決這個問題,請使用以下方法:

Snackbar.make(floating_action_button, "Some snackbar text!", BaseTransientBottomBar.LENGTH_SHORT).setAnchorView(floating_action_button).show();

Irfan Raza代碼的一個小改進:

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

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }
    });

浮動操作按鈕在向下滾動時隱藏,向上滾動時顯示。

看到這個 在這里,它告訴您如何做您想要實現的目標。 您必須在CoordinatorLayoutListView像這樣使用它:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    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">

          <ListView
              android:id="@+id/lvToDoList"
              android:layout_width="match_parent"
              android:layout_height="match_parent"></ListView>

          <android.support.design.widget.FloatingActionButton
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="bottom|right"
              android:layout_margin="16dp"
              android:src="@drawable/ic_done"
              app:layout_anchor="@id/lvToDoList"
              app:layout_anchorGravity="bottom|right|end" />

</android.support.design.widget.CoordinatorLayout>

使用這個類,您可以輕松地為 FAB 設置動畫,在這里我實現了onStopNestedScroll() 方法以在滾動停止時顯示您的 Fab。 我使用 Handler() 將 1000 miliSeconds 設置為延遲;

public class FabBehaviour extends CoordinatorLayout.Behavior<FloatingActionButton> {
    private static final String TAG = "ScrollingFABBehavior";
    Handler mHandler;

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

    public FabBehaviour() {
        super();
    }

    @Override
    public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull final FloatingActionButton child, @NonNull View target, int type) {
        super.onStopNestedScroll(coordinatorLayout, child, target, type);
        if (mHandler == null)
            mHandler = new Handler();


        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
                Log.d("FabAnim", "startHandler()");
            }
        }, 1000);
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
        if (dyConsumed > 0) {
            Log.d("Scrolling", "Up");
            CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
            int fab_bottomMargin = layoutParams.bottomMargin;
            child.animate().translationY(child.getHeight() + fab_bottomMargin).setInterpolator(new LinearInterpolator()).start();
        } else if (dyConsumed < 0) {
            Log.d("Scrolling", "down");
            child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
        }
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
        if (mHandler != null) {
            mHandler.removeMessages(0);
            Log.d("Scrolling", "stopHandler()");
        }
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }


}

your_layout.xml

<android.support.design.widget.FloatingActionButton
        android:id="@+id/imageViewYes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end|right"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_yes"
        app:backgroundTint="@color/white"
        android:scaleType="center"
        app:elevation="6dp"
        app:fabSize="normal"
        app:layout_behavior="com.your.package.FabBehaviour"
        app:pressedTranslationZ="12dp"
        app:rippleColor="@color/gray" />

嘿,需要使用回收視圖來自動隱藏向下滾動時的浮動操作按鈕,為此我們可以以正常方式使用帶有浮動操作按鈕的默認列表視圖,只對 listview.onscroll 偵聽器進行修改,然后我們就可以感覺像回收了

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


        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

            int lastItem = firstVisibleItem + visibleItemCount;
            if (lastItem == totalItemCount) {

                fab.setVisibility(View.INVISIBLE);
            }else {
                fab.setVisibility(View.VISIBLE);
            }
        }
    });

kotlin 中有我的代碼。

class ScrollAwareFABBehavior (val recyclerView: RecyclerView, val floatingActionButton: FloatingActionButton) {

    fun start() {
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)

                if (dy > 0) {
                    if (floatingActionButton!!.isShown) {
                        floatingActionButton?.hide()
                    }
                } else if (dy < 0) {
                    if (!floatingActionButton!!.isShown) {
                        floatingActionButton?.show()
                    }
                }
            }
        })
    }
}

現在,您只需要在構造函數上使用 recyclerView 和 fab 調用 ScrollAwareFABBehavior,然后調用方法 start()。

ScrollAwareFABBehavior(recyclerView = recyclerViewPlaceFormContainer, floatingActionButton = floatingActionButton).start()

Kotlin + 數據綁定適配器

@BindingAdapter("bindAdapter:attachFloatingButton")
fun bindRecyclerViewWithFB(recyclerView: RecyclerView, fb: FloatingActionButton) {
    recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)

            if (dy > 0 && fb.isShown) {
                fb.hide()
            } else if (dy < 0 && !fb.isShown) {
                fb.show()
            }
        }
    })
}

和 xml

    <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/main_recyclerview"
            android:layout_width="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            android:layout_height="wrap_content"
            android:clipToPadding="false"
            android:paddingBottom="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
            android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/main_chips"
            android:layout_marginBottom="8dp"
            **bindAdapter:attachFloatingButton="@{mainFb}"**
            app:layout_constraintBottom_toBottomOf="parent" 
            app:layout_constraintVertical_bias="0.0"/>


    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
            android:id="@+id/main_fb"
            android:layout_width="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            style="@style/Widget.Design.FloatingActionButton"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_height="wrap_content"
            android:layout_margin="18dp"
            android:background="@color/colorPrimaryDark"
            app:icon="@drawable/ic_add_black_24dp"/>

在這里,我為最后一個視圖項添加了額外的填充,以避免與浮動操作按鈕重疊列表項

我在 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();
    }
}

在我看來,實現這一點的最佳方法如下。

public class ScrollingFABBehavior extends FloatingActionButton.Behavior {


private static final String TAG = "ScrollingFABBehavior";

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


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

有關詳細答案,請查看此內容。 在 RecyclerView 滾動時隱藏 FloatingActionButton

對於 Kotlin,它非常簡單(API 23+)

myRecyclerView.setOnScrollChangeListener { _, _, _, _, oldScrollY ->
    if (oldScrollY < 0) myFAB.hide() else myFAB.show()
}

另一種使用 kotlin 擴展的 recycleView 方法。

fun RecyclerView.attachFab(fab : FloatingActionButton) {
    this.addOnScrollListener(object : RecyclerView.OnScrollListener(){
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            if (dy > 0)
                fab.hide()
            else if (dy < 0)
                fab.show()
        }
    })
}

現在您可以使用以下命令將 fab 附加到任何 recycleView:

rv.attachFab(requireActivity().fab)
// in my case i made fab public on activity
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    if (dy > 0 && mFloatingActionButton.getVisibility() == View.VISIBLE) {
        mFloatingActionButton.hide();
    } else if (dy < 0 && mFloatingActionButton.getVisibility() != View.VISIBLE) {
        mFloatingActionButton.show();
    }
}});

只是補充一下,對於NestedScrollView的方法將類似於以下內容:

        // register the extended floating action Button
        final ExtendedFloatingActionButton extendedFloatingActionButton = findViewById(R.id.extFloatingActionButton);
  
        // register the nestedScrollView from the main layout
        NestedScrollView nestedScrollView = findViewById(R.id.nestedScrollView);
  
        // handle the nestedScrollView behaviour with OnScrollChangeListener
        // to extend or shrink the Extended Floating Action Button
        nestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
            @Override
            public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                // the delay of the extension of the FAB is set for 12 items
                if (scrollY > oldScrollY + 12 && extendedFloatingActionButton.isExtended()) {
                    extendedFloatingActionButton.shrink();
                }
  
                // the delay of the extension of the FAB is set for 12 items
                if (scrollY < oldScrollY - 12 && !extendedFloatingActionButton.isExtended()) {
                    extendedFloatingActionButton.extend();
                }
  
                // if the nestedScrollView is at the first item of the list then the
                // extended floating action should be in extended state
                if (scrollY == 0) {
                    extendedFloatingActionButton.extend();
                }
            }
        });

我從GeeksForGeeks獲取了這段代碼

您可以在 ExtendedFloatingActionButton 上使用HideBottomViewOnScrollBehavior

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
            android:id="@+id/main_fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/text_analyze"
            android:layout_margin="@dimen/theme_space"
            app:icon="@drawable/ic_baseline_refresh_24"
            app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
            android:layout_gravity="bottom|end" />

您還可以使用 Gmail 樣式的折疊/展開行為,而不是隱藏 FAB。

創建CollapseFABOnScrollBehavior.java

public class CollapseFABOnScrollBehavior <V extends View> extends CoordinatorLayout.Behavior<V> {
    private final int offsetDp = 8; // You can increase or decrease this value. This offset is necessary for a better user experience.
    private static final int STATE_SCROLLED_DOWN = 1;
    private static final int STATE_SCROLLED_UP = 2;
    private int currentState = STATE_SCROLLED_UP;

    public CollapseFABOnScrollBehavior() {
    }

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

    @Override
    public boolean onStartNestedScroll(
            @NonNull CoordinatorLayout coordinatorLayout,
            @NonNull V child,
            @NonNull View directTargetChild,
            @NonNull View target,
            int axes,
            int type) {
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    @Override
    public void onNestedScroll(
            @NonNull CoordinatorLayout coordinatorLayout,
            @NonNull V child,
            @NonNull View target,
            int dxConsumed,
            int dyConsumed,
            int dxUnconsumed,
            int dyUnconsumed,
            int type,
            @NonNull int[] consumed) {
        int offset = getPixels(child.getContext(), offsetDp);
        if (dyConsumed > offset) {
            collapse(child);
        } else if (dyUnconsumed < 0 || dyConsumed < -offset) {
            expand(child);
        }
    }

    /**
     * Returns true if the current state is scrolled up.
     */
    public boolean isScrolledUp() {
        return currentState == STATE_SCROLLED_UP;
    }


    public void expand(@NonNull V child) {
        if (isScrolledUp()) {
            return;
        }

        currentState = STATE_SCROLLED_UP;
        if(child instanceof ExtendedFloatingActionButton) {
            ((ExtendedFloatingActionButton) child).extend();
        }
    }

    /**
     * Returns true if the current state is scrolled down.
     */
    public boolean isScrolledDown() {
        return currentState == STATE_SCROLLED_DOWN;
    }

    public void collapse(@NonNull V child) {
        if (isScrolledDown()) {
            return;
        }

        currentState = STATE_SCROLLED_DOWN;
        if(child instanceof ExtendedFloatingActionButton) {
            ((ExtendedFloatingActionButton) child).shrink();
        }
    }

    private int getPixels(Context context, int dp) {
        if(context == null) {
            return 0;
        }

        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }
}

將行為添加到您的layout.xml

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
                android:id="@+id/main_fab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/text_analyze"
                android:layout_margin="@dimen/theme_space"
                app:icon="@drawable/ic_baseline_refresh_24"
                app:layout_behavior=".CollapseFABOnScrollBehavior"
                android:layout_gravity="bottom|end" />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM