![](/img/trans.png)
[英]How to hide FloatingActionButton which is anchored to BottomAppBar when the is hidden on scroll
[英]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);
}
});
浮動操作按鈕在向下滾動時隱藏,向上滾動時顯示。
看到這個。 在這里,它告訴您如何做您想要實現的目標。 您必須在CoordinatorLayout
和ListView
像這樣使用它:
<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.