CoordinatorLayout hide toolbar when scrolling only in specific fragment - android

I'm using single Activity approach with multiple fragments, in the main screen I have RecycleView and I want to hide Toolbar when scrolling only in the main screen, since it's single activity and one top level CoordinatorLayout the Toolbar hides when scrolling in all screens.
How to enable "hide toolbar on scroll" in some screens and disable it for others in single activity?

You gotta trace which fragment(screen) is active in your activity and use these functions to hide or show.
fun enableLayoutBehaviour() {
val layoutParams: CoordinatorLayout.LayoutParams = coordinatorLayout.layoutParams
layoutParams.behavior = AppBarLayout.ScrollingViewBehavior()
}
fun disableLayoutBehaviour() {
val layoutParams: CoordinatorLayout.LayoutParams = coordinatorLayout.layoutParams
layoutParams.behavior = null
}

#Yonatan's answer in my case was not enough, when navigating between fragments some views were not visible in the bottom, probably some height misconfiguration.
Enabling and disabling scroll flags for Toolbar works just fine.
public void disableToolbarScrollBehavior() {
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(0);
}
public void enableToolbarScrollBehavior() {
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
}

Related

Disable HideBottomViewOnScrollBehaviour

I currently have a bottom navigation bar inside a Coordinator layout, which I added a HideBottomViewOnScrollBehaviour to. Some screens require the navigation bar to be hidden, which I can achieve by calling the slideUp / slideDown methods from the behaviour object of BottomNavigationBar layout params.
The issue is, even if i'm hiding it programatically, you can reveal it by simply scrolling up again.
I didn't find any solutions, i was thinking there will be something like disabling the behaviour and enabling it on certain screens, but that's not a thing.
Any solutions?
Thanks!
Here are methods to disable/enable scrolling behaviour:
fun enableLayoutBehaviour() {
val params = navView?.layoutParams as CoordinatorLayout.LayoutParams
if (params.behavior == null) {
params.behavior = HideBottomViewOnScrollBehavior<View>()
}
navView?.let {
(params.behavior as HideBottomViewOnScrollBehavior).slideUp(it)
}
}
fun disableLayoutBehaviour() {
val params = navView?.layoutParams as CoordinatorLayout.LayoutParams
navView?.let {
(params.behavior as HideBottomViewOnScrollBehavior).slideDown(it)
}
params.behavior = null
}
You can also just replace NestedScrollView with regular ScrollView on dedicated tabs to disable bottom bar from scrolling.

How to disable "expand" from AppBarLayout in fragment that has a NestedScrollView?

I have two problems:
1) I was able to prevent the "expand" feature when i have no NestedScrollView inside my fragment, but when i do, it keeps expanding, even using:
appBarLayout.setExpanded(false);
appBarLayout.setActivated(false);
There's any way to prevent the expanding of toolbar when i have a NestedScrollView inside a fragment?
2) Even if i don't have a NestedScrollView, i'm still able to expand it when i touch my finger in the toolbar, and scroll down and up. The "expand & collapse" still works.
How can i disable the action of collapse and expand the toolbar when i touch my finger in it and scroll down and up?
Thanks.
Edit1 (More info):
This is the code of my fragment, inside of the FrameLayout.
<android.support.v4.widget.NestedScrollView>
<LinearLayout>
<TextView />
<android.support.v7.widget.RecyclerView />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
And this is my activity structure:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<android.support.v7.widget.Toolbar />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
...
</android.support.v4.widget.DrawerLayout>
Edit 2: Th only question left now is:
There's any way to prevent the expanding of toolbar when i have a NestedScrollView inside a fragment?
I've faced with this problem not so far, and resloved it by changing AppBarLayout height when I need it be collapsable or expandable. So, firstly, you need to define the next two items in your default dimens.xml file:
<dimen name="toolbar_height">56dp</dimen>
<dimen name="toolbar_expanded_height">256dp</dimen> // this can be whatever you need
And then the complete method to prevent AppBarLayout and Toolbar from expanding/collapsing is:
public void disableCollapse() {
appbar.setActivated(false);
//you will need to hide also all content inside CollapsingToolbarLayout
//plus you will need to hide title of it
backdrop.setVisibility(View.GONE);
shadow.setVisibility(View.GONE);
collapsingToolbar.setTitleEnabled(false);
AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams();
p.setScrollFlags(0);
collapsingToolbar.setLayoutParams(p);
collapsingToolbar.setActivated(false);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_height);
appbar.requestLayout();
//you also have to setTitle for toolbar
toolbar.setTitle(title); // or getSupportActionBar().setTitle(title);
}
You may also need to add status bar height to toolbar's height, if you use fitsSystemWindows=true for example, so then you need to change
lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_height);
to
lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_height) + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? getStatusBarHeight() : 0);
And getStatusBarHeight() method implementation is:
protected int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
And, finally, if you want to make your AppBarLayout and Toolbar collapsable/expandable again, you have to use next method:
public void enableCollapse() {
appbar.setActivated(true);
collapsingToolbar.setActivated(true);
//you will need to show now all content inside CollapsingToolbarLayout
//plus you will need to show title of it
backdrop.setVisibility(View.VISIBLE);
shadow.setVisibility(View.VISIBLE);
collapsingToolbar.setTitleEnabled(true);
AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams();
p.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
collapsingToolbar.setLayoutParams(p);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_expanded_height);
appbar.requestLayout();
//you also have to setTitle for toolbar
toolbar.setTitle(title); // or getSupportActionBar().setTitle(title);
}
Hope that helps!
To block the scrolling with your finger over the AppBarLayout you must use the DragCallback interface:
AppBarLayout layout = ...;
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
#Override
public boolean canDrag(#NonNull AppBarLayout appBarLayout) {
return false;
}
});
To prevent the AppBarLayout from scrolling due to NestedScrollView scrolling, you must remove the behaviour from NestedScrollView:
NestedScrollView nestedScrollView = ...;
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) nestedScrollView.getLayoutParams();
params.setBehavior(null);
Another thing you can try is to remove the scroll flags from the AppBarLayout childs:
AppBarLayout layout = ...;
View child = layout.getChildAt(0);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) child.getLayoutParams();
params.setScrollFlags(0);
in your specific fragment onViewCreated method add
private void disableCollapsing() {
AppBarLayout layout = ((HomeActivity) getActivity()).appBarLayout;
View child = layout.getChildAt(0);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) child.getLayoutParams();
params.setScrollFlags(0);
}
and reActive collapsing when destroyed
private void enableCollapsing() {
AppBarLayout layout = ((HomeActivity) getActivity()).appBarLayout;
View child = layout.getChildAt(0);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) child.getLayoutParams();
params.setScrollFlags(1);
}

How to lock CollapsingToolbarLayout from Android support library

I am using Activity class with (usually) one fragment as a content. In the Activity I use CollapsingToolbarLayout as some kind of header for some information and everything works fine. But in some cases (when some fragments are attached) I don't want to show that info, I don't want CollapsingToolbarLayout to open on scroll.
What I want to achieve is to lock CollapsingToolbarLayout, prevent it from opening from the fragment. I am collapsing it programmatically with appBarLayout.setExpanded(false, true);
I came up with a different method as setting the nested scrolling flag only works when dragging the NestedScrollView. The appbar can still be expanded by swiping on the bar itself.
I set this up as a static function in "Utils" class. Obviously the flags you set upon unlocking will depend on which ones are relevant for your use case.
This function assumes you are are starting with an expanded toolbar
public static void LockToolbar(boolean locked, final AppBarLayout appbar, final CollapsingToolbarLayout toolbar) {
if (locked) {
// We want to lock so add the listener and collapse the toolbar
appbar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (toolbar.getHeight() + verticalOffset < 2 * ViewCompat.getMinimumHeight(toolbar)) {
// Now fully expanded again so remove the listener
appbar.removeOnOffsetChangedListener(this);
} else {
// Fully collapsed so set the flags to lock the toolbar
AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
lp.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED);
}
}
});
appbar.setExpanded(false, true);
} else {
// Unlock by restoring the flags and then expand
AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
lp.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
appbar.setExpanded(true, true);
}
}
Well, I managed to solve it myself. The trick is to disable nested scrolling behaviour with ViewCompat.setNestedScrollingEnabled(recyclerView, expanded);
As I am using one fragment in the activity as a content view and putting it on the backstack I simply check when backstack has changed and which fragment is visibile. Note that I NestedScrollView in every fragment to trigger collapsible toolbar. This is my code:
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
NestedScrollView nestedScrollView = (NestedScrollView)findViewById(R.id.nested_scroll_view);
int size = getSupportFragmentManager().getBackStackEntryCount();
if (size >= 1 && nestedScrollView != null) {
if (getSupportFragmentManager().getBackStackEntryAt(size - 1).getName().equals("SpotDetailsFragment")) {
Log.d(LOG_TAG, "Enabling collapsible toolbar.");
ViewCompat.setNestedScrollingEnabled(nestedScrollView, true);
} else {
Log.d(LOG_TAG, "Disabling collapsible toolbar.");
ViewCompat.setNestedScrollingEnabled(nestedScrollView, false);
}
}
}
});
This thread helped me a lot, where another possible solution is presented:
Need to disable expand on CollapsingToolbarLayout for certain fragments

Changing Toolbar and CollapsingToolbarLayout scroll flags programmatically

I have a single Activity android app with lots of fragments. When I'm showing a list screen I want to use the Toolbar with the, app:layout_scrollFlags="scroll|enterAlways" property. And in the detail fragments I want to use the CollapsingToolbarLayout with an image in it. Since it's a single Activity app, I have only one Toolbar. Is it possible to modify my layout programmatically to suit both cases?
Yes. Let's say you are going from the CollapsingToolbarLayout fragment to the Toolbar one.
You collapse your AppBarLayout using AppBarLayout.setExpanded(false);
You change the scroll flags to fit your needs.
AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
p.setScrollFlags(...);
toolbar.setLayoutParams(p);
Same goes for the CollapsingToolbarLayout if necessary. I guess it should be something like:
collapsingToolbarParams.setScrollFlags(0); //no flags for ctl
toolbarParams.setScrollFlags(SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS); //new flags for toolbar
I found it working
public void disableToolBarScrolling() {
CollapsingToolbarLayout toolbar = findViewById(R.id.collap_toolbar);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(0);
}
public void enableToolBarScrolling() {
CollapsingToolbarLayout toolbar = findViewById(R.id.collap_toolbar);
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS);
}
Works for me.
public void enableToolBarScrolling(CollapsingToolbarLayout toolbar) {
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS);
toolbar.setLayoutParams(params);
}

Programmatically collapse or expand CollapsingToolbarLayout

Simple question, but I can't find an answer. How can I collapse or expand the CollapsingToolbarLayout programmatically?
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Using Support Library v23, you can call appBarLayout.setExpanded(true/false).
Further reading: AppBarLayout.setExpanded(boolean)
I use this code for collapsing toolbar. Still cannot find a way to expand it.
public void collapseToolbar(){
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbarLayout.getLayoutParams();
behavior = (AppBarLayout.Behavior) params.getBehavior();
if(behavior!=null) {
behavior.onNestedFling(rootLayout, appbarLayout, null, 0, 10000, true);
}
}
Edit 1: The same function with negative velocityY but the toolbar is not expanded 100% and false for last param should work
public void expandToolbar(){
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbarLayout.getLayoutParams();
behavior = (AppBarLayout.Behavior) params.getBehavior();
if(behavior!=null) {
behavior.onNestedFling(rootLayout, appbarLayout, null, 0, -10000, false);
}
}
Edit 2: This code do the trick for me
public void expandToolbar(){
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbarLayout.getLayoutParams();
behavior = (AppBarLayout.Behavior) params.getBehavior();
if(behavior!=null) {
behavior.setTopAndBottomOffset(0);
behavior.onNestedPreScroll(rootLayout, appbarLayout, null, 0, 1, new int[2]);
}
}
setTopAndBottomOffset do expand the toolbar
onNestedPreScroll do show the content inside expanded toolbar
Will try to implement Behavior by myself.
You can define how much it expands or collapses with your custom animator.
Just use the setTopAndBottomOffset(int).
Here is an example:
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBar.getLayoutParams();
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
if (behavior != null) {
ValueAnimator valueAnimator = ValueAnimator.ofInt();
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
behavior.setTopAndBottomOffset((Integer) animation.getAnimatedValue());
appBar.requestLayout();
}
});
valueAnimator.setIntValues(0, -900);
valueAnimator.setDuration(400);
valueAnimator.start();
}
I've written a small extension to AppBarLayout. It allows for expanding and collapsing of the CollapsibleToolbarLayout both with and without animation. It seems to be doing it quite right.
Feel free to try it out.
Just use it instead of your AppBarLayout, and you can call methods responsible for expanding or collapsing of the CollapsingToolbarLayout.
It's working exactly as expected in my project, but you might need to tweak the fling/scroll values in the perform... methods (especially in performExpandingWithAnimation()) to fit perfectly with your CollapsibleToolbarLayout.
Use mAppBarLayout.setExpanded(true) to expand Toolbar and use mAppBarLayout.setExpanded(false) to collapse Toolbar.
If you want to change CollapsingToolbarLayout height programmatically then just use mAppBarLayout.setLayoutParams(params);
Expand:
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
params.height = 3*200; // HEIGHT
mAppBarLayout.setLayoutParams(params);
mAppBarLayout.setExpanded(true);
Collapse:
CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
params.height = 3*80; // HEIGHT
mAppBarLayout.setLayoutParams(params);
mAppBarLayout.setExpanded(false);
for the ones who wants to work with onNestedPreScroll and get error like me.
i get NullPointerException in onCreate with out this line
CoordinatorLayout coordinator =(CoordinatorLayout)findViewById(R.id.tab_maincontent);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
//below line
params.setBehavior(new AppBarLayout.Behavior() {});
and doesn't work properly with this.
but i work around this problem with
in onCreate :
scrollToolbarOnDelay();
and...
public void scrollToolbarOnDelay() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.tab_appbar);
CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.tab_maincontent);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
if(behavior!=null)
behavior.onNestedPreScroll(coordinator, appBarLayout, null, 0, 100, new int[]{0, 0});
else
scrollToolbarOnDelay()
}
}, 100);
}
Try this...
Expand
appBarLayout.setExpanded(true, true);
To recall
appBarLayout.setExpanded(false, true);
To expand/collapse AppBarLayout programmatically:
fun expandAppBarLayout(expand: Boolean, isAnimationEnabled: Boolean){
appBarLayout.setExpanded(expand, isAnimationEnabled);
}
This may help to expand or collapse :
appBarLayout.setActivated(true);
appBarLayout.setExpanded(true, true);
i have using this
private fun collapseAppbar() {
scrollView.postDelayed(Runnable {
scrollView?.smoothScrollTo(50, 50)
}, 400)
}

Categories

Resources