Programmatically collapse or expand CollapsingToolbarLayout - android

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

Related

CoordinatorLayout hide toolbar when scrolling only in specific fragment

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

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

Collapsing Toolbar Layout - full height Image and scrolled at start

I have got a layout quite similar to this one: http://antonioleiva.com/collapsing-toolbar-layout/ - a classic approach to the Collapsing Toolbar.
I would like to extend it with following feature:
The ImageView is full screen height and at activity starts it is automatically scrolled half of it height down. When activity starts and user will scroll down, it will behave the old way, but (at activity starts) when he scrolls up, he can scroll all the way up to make the image full screen height size.
What kid of steps I need to take to make it behave the way I imagined?
Here is the the general Idea.
Activity:
public void setupMovingBar(final Boolean full) {
final Display dWidth = getWindowManager().getDefaultDisplay();
appBarLayout.post(new Runnable() {
#Override
public void run() {
int heightPx = dWidth.getHeight();
if (!full) {
heightPx = dWidth.getHeight() - (dWidth.getHeight() * 1 / 3);
}
setAppBarOffset(heightPx);
}
});
}
private void setAppBarOffset(int offsetPx) {
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.onNestedPreScroll(clContent, appBarLayout, null, 0, offsetPx, new int[]{0, 0});
}

CollapsingToolbarLayout expand programmatically animation duration

I'm using CollapsingToolbarLayout in my application in Android. My app's minimum requirement API is 9.
I need the collapsed toolbar to be expanded when the user clicks in the collapsed one, just like in latest Gmail Calendar's app. So I set an onClickListener and inside it I do the following:
public void onClick(View v) {
if(toolbarExpanded) {
mAppBar.setExpanded(false, true);
} else {
mAppBar.setExpanded(true, true);
}
toolbarExpanded = !toolbarExpanded;
}
Which is working quite well but my problem is that the animation that it's running is slow, meaning a bad user experience.
Is there anyway to change the duration or to define a custom animation for this?
Thank you in advance.
Note: this answer is based on android design library v25.0.0.
You can call the private method animateOffsetTo of the AppBarLayout.Behavior of your NestedScrollView with reflection. This method has a velocity parameter that has an impact on the animation duration.
private void expandAppBarLayoutWithVelocity(AppBarLayout.Behavior behavior, CoordinatorLayout coordinatorLayout, AppBarLayout appBarLayout, float velocity) {
try {
//With reflection, we can call the private method of Behavior that expands the AppBarLayout with specified velocity
Method animateOffsetTo = AppBarLayout.Behavior.getClass().getDeclaredMethod("animateOffsetTo", CoordinatorLayout.class, AppBarLayout.class, int.class, float.class);
animateOffsetTo.setAccessible(true);
animateOffsetTo.invoke(behavior, coordinatorLayout, appBarLayout, 0, velocity);
} catch (Exception e) {
e.printStackTrace();
//If the reflection fails, we fall back to the public method setExpanded that expands the AppBarLayout with a fixed velocity
Log.e(TAG, "Failed to get animateOffsetTo method from AppBarLayout.Behavior through reflection. Falling back to setExpanded.");
appBarLayout.setExpanded(true, true);
}
}
To get the Behavior, you need to fetch it from the LayoutParams of your AppBarLayout.
AppBarLayout appBarLayout = (AppBarLayout)findViewById(R.id.app_bar);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = params.getBehavior();
To expand with animation use
AppBarLayout.setExpanded(true,true);
To Collapse with animation use
AppBarLayout.setExpanded(false,true);

params.getBehaviour() returns null value

I was playing with the new Android Design Library. The CollapsingToolbarLayout works perfectly. However, I am having trouble setting default state of toolbar as Collapsed.
I am trying to implement the solution shown here and here
I am calling following code in my onResume of Activity:
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
if(behavior!=null)
{
Log.d("DEBUG", "Behaviour is Not Null ");
int[] consumed = new int[2];
behavior.onNestedPreScroll(coordinator, appBarLayout, null, 0, 1000,consumed);
// behavior.onNestedFling(coordinator, appBarLayout, null, 0, 10000, true);
}
else
Log.d("DEBUG", "Behaviour is Null " );
However, the behaviour returned by params is null.
My xml is code same as here, except i am not using drawer and CordinatorLayout is my root Layout.
EDIT: I earlier tried switching AppBarLayout.Behavior to AppBarLayout.ScrollingViewBehavior and setting layout_behavior for AppBarLayout to #string/appbar_scrolling_view_behavior, but it resulted in weird layout.
Robin's answer works nicely. To Complement that, the behavior can also set in xml using following tag in AppBarLayout:
app:layout_behavior="android.support.design.widget.AppBarLayout$Behavior"
You have to set a layout behavior before.
Just use following code at your onCreate method:
((CoordinatorLayout.LayoutParams) YOUR_LAYOUT.getLayoutParams()).setBehavior(new AppBarLayout.Behavior() {});

Categories

Resources