I know how to change the height of a Bottom Sheet.
There is no problem to increase the height of a bottom sheet. However I cannot decrease its height with the following code .
bottomSheetBehavior.setPeekHeight(peekHeight); // peekHeight < previous height
bottomSheetBehavior.setState(STATE_COLLAPSED);
Anyone encountered the same problem ?
I am trying to do the same and I don't have such problem. I could easily increase and decrease my BottomSheetDialogFragment height. Here is my code of two methods of my fragment:
private BottomSheetBehavior.BottomSheetCallback bottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
dismiss();
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
};
public static BottomSheetFragment newInstance() {
return new BottomSheetFragment();
}
#Override
public void setupDialog(Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.bottom_sheet_dialog_content_view, null);
dialog.setContentView(contentView);
CoordinatorLayout.LayoutParams layoutParams = ((CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams());
CoordinatorLayout.Behavior behavior = layoutParams.getBehavior();
if (behavior != null && behavior instanceof BottomSheetBehavior) {
((BottomSheetBehavior) behavior).setBottomSheetCallback(bottomSheetCallback);
((BottomSheetBehavior) behavior).setPeekHeight(getResources().getDimensionPixelSize(R.dimen.bottom_sheet_height) / 4);
}
initRecyclerView(contentView);
}
Related
I have a bottom sheet that has inside a listview, I don't want to have the behaviour to expand or to dismiss, I just want to keep it at the fixed size, Now it shows at the size I want (70% of screen) but on slide up or down it changes its state.
Is there a way i can do this?
I have tried:
BottomSheetBehavior.BottomSheetCallback bottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
// dismiss();
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
};
// bottomSheetBehavior.setBottomSheetCallback(bottomSheetCallback);
if (behavior != null && behavior instanceof BottomSheetBehavior) {
((BottomSheetBehavior) behavior).setBottomSheetCallback(bottomSheetCallback);
((BottomSheetBehavior) behavior).setPeekHeight(((RestaurantsActivity) getActivity()).getHeightForFragment());
}
I have Bottomsheetdialog with Custom view having EditText and on EditText scrolling bottom sheet goes down, How to disable BottomSheetDialog dragging. Any Help Appreciated.
I might be late, but it works fine for me:
#Override
public void setupDialog(final Dialog dialog, int style) {
super.setupDialog(dialog, style);
// This should do the job
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(true);
}
Simple solution, It solved two problem I had.
1- It block the dragging event.
2- It solves the listView scrolling problem
CoordinatorLayout.Behavior<View> behavior;
View profile_config_layout_bottom_sheet = findViewById(R.id.list_view_audience_profile_config_layout);
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) profile_config_layout_bottom_sheet.getLayoutParams();
behavior = layoutParams.getBehavior();
assert behavior != null;
((BottomSheetBehavior<View>) behavior).addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
((BottomSheetBehavior<View>) behavior).setState(BottomSheetBehavior.STATE_EXPANDED);
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {}
});
Show the dialog with:
((BottomSheetBehavior) behavior).setState(BottomSheetBehavior.STATE_EXPANDED);
Standard android BottomSheetBehavior has tree state: hidden, collapsed and expanded.
I want to allow user to "leave" bottom sheet between collapsed and expanded. Now, with the default behavior, it will snap to collapsed or expanded based which is closest. How should I disable this snap functionality?
I will present a way to achievie such functionality for a View extending BottomSheetDialogFragment.
Expanding:
First of all overrive onResume:
#Override
public void onResume() {
super.onResume();
addGlobaLayoutListener(getView());
}
private void addGlobaLayoutListener(final View view) {
view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
setPeekHeight(v.getMeasuredHeight());
v.removeOnLayoutChangeListener(this);
}
});
}
public void setPeekHeight(int peekHeight) {
BottomSheetBehavior behavior = getBottomSheetBehaviour();
if (behavior == null) {
return;
}
behavior.setPeekHeight(peekHeight);
}
What the code above is supposed to do is just setting the BottomSheet peekHeight to the heigth of the view. The key here is the function getBottomSheetBehaviour(). The implementation is below:
private BottomSheetBehavior getBottomSheetBehaviour() {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) ((View) getView().getParent()).getLayoutParams();
CoordinatorLayout.Behavior behavior = layoutParams.getBehavior();
if (behavior != null && behavior instanceof BottomSheetBehavior) {
((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback);
return (BottomSheetBehavior) behavior;
}
return null;
}
This just check if the parent of View has 'CoordinatorLayout.LayoutParams' set. If yes, sets appropriate BottomSheetBehavior.BottomSheetCallback (which is needed in the next part), and more importantly returns the CoordinatorLayout.Behavior, which is supposed to be BottomSheetBehavior.
Collapsing:
Here a [`BottomSheetBehavior.BottomSheetCallback.onSlide (View bottomSheet, float slideOffset)``](https://developer.android.com/reference/android/support/design/widget/BottomSheetBehavior.BottomSheetCallback.html#onSlide(android.view.View, float)) is just exactly what is needed. From the [documentation](https://developer.android.com/reference/android/support/design/widget/BottomSheetBehavior.BottomSheetCallback.html#onSlide(android.view.View, float)):
Offset increases as this bottom sheet is moving upward. From 0 to 1 the sheet is between collapsed and expanded states and from -1 to 0 it is between hidden and collapsed states.
This means, that just checking the second parameter is needed for collapse detection:
define BottomSheetBehavior.BottomSheetCallback in the same class:
private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
dismiss();
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
if (slideOffset < 0) {
dismiss();
}
}
};
I am working on app in some fragment i want to hide FloatingActionButtton.
When i set android:visibility="gone". Behavior animation show me FloatingActionButtton when i swipe up and down. is there is any way i can disable/enable FloatingActionButtton behavior.
Thank you advance.
here is my code
QuickReturnFooterBehavior.java
package com.app.common;
import android.animation.Animator;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewPropertyAnimator;
#SuppressWarnings("unused")
public class QuickReturnFooterBehavior extends CoordinatorLayout.Behavior<View> {
private static final FastOutSlowInInterpolator INTERPOLATOR = new FastOutSlowInInterpolator();
private int mDySinceDirectionChange;
private boolean mIsShowing;
private boolean mIsHiding;
public QuickReturnFooterBehavior() {
}
public QuickReturnFooterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
#Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if (dy > 0 && mDySinceDirectionChange < 0
|| dy < 0 && mDySinceDirectionChange > 0) {
// We detected a direction change- cancel existing animations and reset our cumulative delta Y
child.animate().cancel();
mDySinceDirectionChange = 0;
}
mDySinceDirectionChange += dy;
if (mDySinceDirectionChange > child.getHeight()
&& child.getVisibility() == View.VISIBLE
&& !mIsHiding) {
hide(child);
} else if (mDySinceDirectionChange < 0
&& child.getVisibility() == View.GONE
&& !mIsShowing) {
show(child);
}
}
/**
* Hide the quick return view.
*
* Animates hiding the view, with the view sliding down and out of the screen.
* After the view has disappeared, its visibility will change to GONE.
*
* #param view The quick return view
*/
private void hide(final View view) {
mIsHiding = true;
ViewPropertyAnimator animator = view.animate()
.translationY(view.getHeight())
.setInterpolator(INTERPOLATOR)
.setDuration(200);
animator.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {}
#Override
public void onAnimationEnd(Animator animator) {
// Prevent drawing the View after it is gone
mIsHiding = false;
view.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animator) {
// Canceling a hide should show the view
mIsHiding = false;
if (!mIsShowing) {
show(view);
}
}
#Override
public void onAnimationRepeat(Animator animator) {}
});
animator.start();
}
/**
* Show the quick return view.
*
* Animates showing the view, with the view sliding up from the bottom of the screen.
* After the view has reappeared, its visibility will change to VISIBLE.
*
* #param view The quick return view
*/
private void show(final View view) {
mIsShowing = true;
ViewPropertyAnimator animator = view.animate()
.translationY(0)
.setInterpolator(INTERPOLATOR)
.setDuration(200);
animator.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
view.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animator) {
mIsShowing = false;
}
#Override
public void onAnimationCancel(Animator animator) {
// Canceling a show should hide the view
mIsShowing = false;
if (!mIsHiding) {
hide(view);
}
}
#Override
public void onAnimationRepeat(Animator animator) {}
});
animator.start();
}
}
and XML
<android.support.design.widget.FloatingActionButton
app:layout_behavior="com.app.common.QuickReturnFooterBehavior"
android:id="#+id/fab_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:src="#drawable/ic_action_quick_response_code"
app:backgroundTint="#color/text_gray"
app:descriptionText="#string/add_friend"
app:elevation="3dp"
app:borderWidth="0dp"
/>
Finally I find it solution and I want to share with you.
You can enable/disable FloatingActionButton Behavior
Disable Behavior
FloatingActionButton fab2 = (FloatingActionButton)findViewById(R.id.fab2);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) fab2.getLayoutParams();
params.setBehavior(null);
fab2.requestLayout();
fab2.setVisibility(View.GONE);
Enable Behavior
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) fab2.getLayoutParams();
params.setBehavior(new QuickReturnFooterBehavior());
fab2.requestLayout();
fab2.setVisibility(View.VISIBLE);
Edited: More Reusable Class
public class CoordinateBehaviourUtils {
public static void enableDisableViewBehaviour(View view,CoordinatorLayout.Behavior<View> behavior,boolean enable){
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
params.setBehavior(behavior);
view.requestLayout();
view.setVisibility((enable ? View.VISIBLE: View.GONE));
}
}
How To Enable Using Common Class
FloatingActionButton fab2 = (FloatingActionButton)findViewById(R.id.fab2);
CoordinateBehaviourUtils.enableDisableViewBehaviour(fab2,new QuickReturnFooterBehavior(),true);
How To Disable Using Common Class
FloatingActionButton fab2 = (FloatingActionButton)findViewById(R.id.fab2);
CoordinateBehaviourUtils.enableDisableViewBehaviour(fab2,null,false);
Hope it will solve your problem :)
There is no difference while setting up the visibility of a FAB, it works likely other controls.
0 is for VISIBLE
4 is for INVISIBLE
8 is for GONE
You can try something this;
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
// to make is disable for some requirement
fab.setVisibility(View.GONE);
// to make it enable
fab.setVisibility(View.VISIBLE);
I am having a nestedscrollview with content like some linearlayouts and textviews.
I am using a floatingactionbutton library for some reasons, as well. So I can't use any behavior for it.
I don't know how I should handle the scrollchangelistener from scrollview to hide and show the fab dynamically like a behavior.
Any suggestions how to hide and show the fab while scrolling?
Simple add this code below to your NestedScrollView ScrollChangeListener:
NestedScrollView nsv = v.findViewById(R.id.nsv);
nsv.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
#Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (scrollY > oldScrollY) {
fab.hide();
} else {
fab.show();
}
}
});
Create FabScrollBehavior class
public class FabScrollBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
private int toolbarHeight;
public FabScrollBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
this.toolbarHeight = AppUtil.getToolbarHeight(context);
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
return dependency instanceof AppBarLayout;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
if (dependency instanceof AppBarLayout) {
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
int distanceToScroll = fab.getHeight() + fabBottomMargin;
float ratio = (float)dependency.getY()/(float)toolbarHeight;
fab.setTranslationY(-distanceToScroll * ratio);
}
return true;
}
}
Where AppUtil.getToolbarHeight(context) is -
public static int getToolbarHeight(Context context) {
final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(
new int[]{R.attr.actionBarSize});
int toolbarHeight = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
return toolbarHeight;
}
then in your layout add to FloatingActionButton layout_behavior:
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab_task_accept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_accepted"
app:layout_behavior="pass.to.your.FabScrollBehavior.Class"
app:theme="#style/Widget.AppTheme.Fab"/>
The whole layout looks like
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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"
android:animateLayoutChanges="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Widget.AppTheme.AppBarOverlay">
<include
layout="#layout/include_layout_toolbar_scroll"/>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/include_layout_content_with_nestedscroll"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab_task_accept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_accepted"
app:layout_behavior="pass.to.FabScrollBehavior.Class"
app:theme="#style/Widget.AppTheme.Fab"/>
</android.support.design.widget.CoordinatorLayout>
Implemented from https://mzgreen.github.io/2015/02/15/How-to-hideshow-Toolbar-when-list-is-scroling(part1)/
define variable type int in your Activity or fragment to set previous Scroll from ScrollView then use this method to listen change scroll in ScrollView Class
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
// previousScrollY this variable is define in your Activity or Fragment
if (scrollView.getScrollY() > previousScrollY && floatingActionButton.getVisibility() == View.VISIBLE) {
floatingActionButton.hide();
} else if (scrollView.getScrollY() < previousScrollY && floatingActionButton.getVisibility() != View.VISIBLE) {
floatingActionButton.show();
}
previousScrollY = scrollView.getScrollY();
}
});
will work done all version of android
After spending such time i have found the solution for it.
It may work in all situations. Though it is a hack not the proper solution but you can apply it to make this thing work.
As we know setOnScrollChangeListener will only work if minimum api 23, so what if my minimum api level is less then 23.
So I found out solution from stack overflow that we can use getViewTreeObserver().addOnScrollChangedListener for that so this will be compatible solution for all devices.
Now let's move to the final solution of over problem "Hide fab button when nested scroll view scrolling and Show fab button when nested scroll view in ideal state"
So for that we can use Handler with postDelayed to slove this issue.
Define on variable in you context private int previousScrollY = 0;
Then use getViewTreeObserver().addOnScrollChangedListener to your nested scroll view like this.
NESTEDSCROLLVIEW.getViewTreeObserver().addOnScrollChangedListener(new
ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (NESTEDSCROLLVIEW.getScrollY() == previousScrollY) {
FABBUTTON.setVisibility(View.VISIBLE);
} else {
FABBUTTON.setVisibility(View.INVISIBLE);
}
}
}, 10);
previousScrollY = NESTEDSCROLLVIEW.getScrollY();
}
});
Now you are ready to go....
You can use this listener to observe and hide FAB when scrolling.
nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (nestedScrollView != null) {
if (nestedScrollView.getChildAt(0).getBottom() <= (nestedScrollView.getHeight() + nestedScrollView.getScrollY())) {
fab.setVisibility(View.INVISIBLE);
} else {
fab.setVisibility(View.VISIBLE);
}
}
}
});