I wanted to prevent the user from expanding and collapsing the toolbar by dragging his finger while still keeping the collapsing/expanding behaviour to work programmatically. Took me longer than expected to figure this out, however the solution turned out to be pretty easy, this is the result
The trick is a good understanding of CoordinatorLayout and Behavior. These are the two components responsible for the magic happening when using CollapsingToolbarLayout, in fact you always need a CoordinatorLayout when doing this. There is nothing really interesting going on in the xml layout, all the magic happens through code. I created a custom Behavior for the AppBarLayout which allows me to
- Block drag events on the toolbar
- Prevent the AppBarLayout from reacting to nested scroll events.
Nested scroll events are fired by the NestedScrollView that holds my content, in this case two checkboxes and one button. These events bubble their way up to the CoordinatorLayout, which then orchestrates the whole material magic by asking every view for its behaviour and acting accordingly. Every view inside a CoordinatorLayout can provide a behavior and this encodes how that view will react to scroll events.
My custom Behavior for AppBarLayout looks like this
Prevent the user from dragging the toolbar to expand or collapse the AppBarLayout
To block user interactions when the toolbar is dragged I set a drag callback which returns the enabled state of the interaction. The state is set programmatically so it is possible to enable and disable user interactions from the code. The system will use this call to determine whether or not to accept drag events.
Prevent the user from scrolling the content to expand or collapse the AppBarLayout
I achieve this by accepting or refusing nested scroll events. The
onStartNestedScroll() method does exactly that. This is also driven by a flag which I can set from my code. When CoordinatorLayout asks AppBarLayout how it wants to deal with nested scroll events I simply say that it does or it does not, depending on the flag. If the flag is false CoordinatorLayout will stop further dispatching of callbacks related to nested scroll events.
Setting the new Behavior for AppBarLayout
With the Behavior in place I just had to actually use it
That’s pretty much it, I hope this was useful and please let me know in the comments!