CollapsingToolbarLayout - shadow only when scrolled [duplicate] - android

I've created an AppBar layout like this
<android.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/appbar_layout"
android:layout_height="#dimen/app_bar_height"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="20dp">
<android.support.design.widget.CollapsingToolbarLayout...>
</android.support.design.widget.AppBarLayout>
it works and casts a shadow in the LinearLayout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</LinearLayout>
However when I put it into the CoordinatorLayout shadow is gone:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</android.support.design.widget.CoordinatorLayout>
How can I make appbar to show its shadow again?

This is actually an implementation detail of CollapsingToolbarLayout, as seen in the source code:
if (Math.abs(verticalOffset) == scrollRange) {
// If we have some pinned children, and we're offset to only show those views,
// we want to be elevate
ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
// Otherwise, we're inline with the content
ViewCompat.setElevation(layout, 0f);
}
Which removes the elevation when the CollapsingToolbarLayout is showing non-pinned elements - by default, it'll only have elevation when only pinned children are visible.

the reason is above,try this to solve:
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//some other code here
ViewCompat.setElevation(appBarLayout, The Elevation In Px);
}
});

The solution is to use app:elevation=0dp to remove the default elevation and set android:translationZ to the elevation you want.
Note : The code below uses the latest AndroidX / Material libraries and might not work if you're using the old support library
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:translationZ="8dp"
app:elevation="0dp">
<!--
* `app:elevation=0dp` disables the default shadow that is automatically added on
scroll ; other values e.g. `6dp` are ignored despite what the official doc says
(see below)
* so instead we're using `android:translationZ` to add a shadow with a custom
elevation
-->
The documentation for AppBarLayout # setTargetElevation() states that you can set a custom elevation value using the app:elevation attribute, but it didn't work for me for values greater than 0dp, so I'm using translationZ as a workaround.

setTargetElevation() is now deprecated for AppBarLayout.
The new correct implementation for applying custom elevation to an AppBarLayout based on the state of the layout is to use a StateListAnimator.
material-components uses this as you can see here
I've added an example implementation of always showing AppBarLayout elevation here in this gist.
All you need is to 1. create a custom state list animator under /res/animator and 2. set the AppBarLayout's StateListAnimator like so:
appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)

Related

Why there is no shadow under AppBarLayout despite having elevation [duplicate]

I've created an AppBar layout like this
<android.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/appbar_layout"
android:layout_height="#dimen/app_bar_height"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="20dp">
<android.support.design.widget.CollapsingToolbarLayout...>
</android.support.design.widget.AppBarLayout>
it works and casts a shadow in the LinearLayout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</LinearLayout>
However when I put it into the CoordinatorLayout shadow is gone:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</android.support.design.widget.CoordinatorLayout>
How can I make appbar to show its shadow again?
This is actually an implementation detail of CollapsingToolbarLayout, as seen in the source code:
if (Math.abs(verticalOffset) == scrollRange) {
// If we have some pinned children, and we're offset to only show those views,
// we want to be elevate
ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
// Otherwise, we're inline with the content
ViewCompat.setElevation(layout, 0f);
}
Which removes the elevation when the CollapsingToolbarLayout is showing non-pinned elements - by default, it'll only have elevation when only pinned children are visible.
the reason is above,try this to solve:
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//some other code here
ViewCompat.setElevation(appBarLayout, The Elevation In Px);
}
});
The solution is to use app:elevation=0dp to remove the default elevation and set android:translationZ to the elevation you want.
Note : The code below uses the latest AndroidX / Material libraries and might not work if you're using the old support library
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:translationZ="8dp"
app:elevation="0dp">
<!--
* `app:elevation=0dp` disables the default shadow that is automatically added on
scroll ; other values e.g. `6dp` are ignored despite what the official doc says
(see below)
* so instead we're using `android:translationZ` to add a shadow with a custom
elevation
-->
The documentation for AppBarLayout # setTargetElevation() states that you can set a custom elevation value using the app:elevation attribute, but it didn't work for me for values greater than 0dp, so I'm using translationZ as a workaround.
setTargetElevation() is now deprecated for AppBarLayout.
The new correct implementation for applying custom elevation to an AppBarLayout based on the state of the layout is to use a StateListAnimator.
material-components uses this as you can see here
I've added an example implementation of always showing AppBarLayout elevation here in this gist.
All you need is to 1. create a custom state list animator under /res/animator and 2. set the AppBarLayout's StateListAnimator like so:
appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)

ToolBar disappears when setting elevation for AppBarLayout

My ToolBar disappears when setting elevation for AppBarLayout. Here's the layout.
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="#dimen/appbar_height"
app:elevation="0dp"
android:background="#color/transparent">
<android.support.v7.widget.Toolbar
style="#style/ToolBarStyle"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:background="#drawable/backgorund_toolbar_tranluscent"
android:minHeight="#dimen/abc_action_bar_default_height_material" />
</android.support.design.widget.AppBarLayout>
I have tried values like 0dp, 0.1dp and 4dp for app:elevation. What's happening here? Is it a support library bug? I'm using 24.0.0.
Answer from #Zeeshan is totally right.
as an extra here is a sample code that works
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
StateListAnimator stateListAnimator = new StateListAnimator();
stateListAnimator.addState(new int[0], ObjectAnimator.ofFloat(appBarLayout, "elevation", 0.1f));
appBarLayout.setStateListAnimator(stateListAnimator);
}
I had to set elevation to 0.1 because setting it to 0 wasn't working, the whole Layout was disappearing.
New Update: In Appcompat v24.0.0, you can not set elevation to AppBarLayout using setElevation() and app:elevation as these are deprecated.
You have to use stateListAnimator property to set elevation now.
Note: set duration to 1ms in StateListAnimator in order to avoid delay in Elevation Drawing.
AppBarLayout elevation change is delayed on appCompat v24.0.0

CoordinatorLayout and AppBarLayout elevation

I've created an AppBar layout like this
<android.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/appbar_layout"
android:layout_height="#dimen/app_bar_height"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="20dp">
<android.support.design.widget.CollapsingToolbarLayout...>
</android.support.design.widget.AppBarLayout>
it works and casts a shadow in the LinearLayout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</LinearLayout>
However when I put it into the CoordinatorLayout shadow is gone:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</android.support.design.widget.CoordinatorLayout>
How can I make appbar to show its shadow again?
This is actually an implementation detail of CollapsingToolbarLayout, as seen in the source code:
if (Math.abs(verticalOffset) == scrollRange) {
// If we have some pinned children, and we're offset to only show those views,
// we want to be elevate
ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
// Otherwise, we're inline with the content
ViewCompat.setElevation(layout, 0f);
}
Which removes the elevation when the CollapsingToolbarLayout is showing non-pinned elements - by default, it'll only have elevation when only pinned children are visible.
the reason is above,try this to solve:
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//some other code here
ViewCompat.setElevation(appBarLayout, The Elevation In Px);
}
});
The solution is to use app:elevation=0dp to remove the default elevation and set android:translationZ to the elevation you want.
Note : The code below uses the latest AndroidX / Material libraries and might not work if you're using the old support library
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:translationZ="8dp"
app:elevation="0dp">
<!--
* `app:elevation=0dp` disables the default shadow that is automatically added on
scroll ; other values e.g. `6dp` are ignored despite what the official doc says
(see below)
* so instead we're using `android:translationZ` to add a shadow with a custom
elevation
-->
The documentation for AppBarLayout # setTargetElevation() states that you can set a custom elevation value using the app:elevation attribute, but it didn't work for me for values greater than 0dp, so I'm using translationZ as a workaround.
setTargetElevation() is now deprecated for AppBarLayout.
The new correct implementation for applying custom elevation to an AppBarLayout based on the state of the layout is to use a StateListAnimator.
material-components uses this as you can see here
I've added an example implementation of always showing AppBarLayout elevation here in this gist.
All you need is to 1. create a custom state list animator under /res/animator and 2. set the AppBarLayout's StateListAnimator like so:
appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)

remove shadow below AppBarLayout widget android

When using AppBarLayout widget in design support library, a shadow appears on the bottom of the toolbar. How can I remove that shadow?
Simply use app:elevation="0dp" inside "AppBarLayout" to remove the shadow. It has always worked for me. Hope it works for you.
this problem only occurs when api version >= 21, try below codes:
appBar.setOutlineProvider(null);
remember to check api version
EDIT :
Below is the source code of setOutlineProvider.
/**
* Sets the {#link ViewOutlineProvider} of the view, which generates the Outline that defines
* the shape of the shadow it casts, and enables outline clipping.
* <p>
* The default ViewOutlineProvider, {#link ViewOutlineProvider#BACKGROUND}, queries the Outline
* from the View's background drawable, via {#link Drawable#getOutline(Outline)}. Changing the
* outline provider with this method allows this behavior to be overridden.
* <p>
* If the ViewOutlineProvider is null, if querying it for an outline returns false,
* or if the produced Outline is {#link Outline#isEmpty()}, shadows will not be cast.
* <p>
* Only outlines that return true from {#link Outline#canClip()} may be used for clipping.
*
* #see #setClipToOutline(boolean)
* #see #getClipToOutline()
* #see #getOutlineProvider()
*/
public void setOutlineProvider(ViewOutlineProvider provider) {
mOutlineProvider = provider;
invalidateOutline();
}
It is said that If the ViewOutlineProvider is null, if querying it for an outline returns false, or if the produced Outline is {#link Outline#isEmpty()}, shadows will not be cast.
So, if you want to remove shadow, you'd better use this method instead of setting app:elevation. It seems like that changing the elevation to remove shadow is a kind of side effect. And changing the elevation may cause some other problems in some cases.
For all those who do not want to use bringToFront() and elevation="0dp" makes the toolbar disappear:
app:elevation="0dp" combinded with android:translationZ="0.1dp" worked for me.
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
app:elevation="0dp"
android:translationZ="0.1dp"
>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#null"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
With latest appcompat versions, the trick setting app:elevation="0.1dp" in xml doesn't work any more.
So far I have found two solutions.
Instead of setting app:elevation, try to use a stateListAnimator. For example, in code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
StateListAnimator stateListAnimator = new StateListAnimator();
stateListAnimator.addState(new int[0], ObjectAnimator.ofFloat(appBarLayout, "elevation", 0.1f));
appBarLayout.setStateListAnimator(stateListAnimator);
}
An easier way is you still set app:elevation="0dp" in xml as normal, but in code:
appBarLayout.bringToFront();
Credit goes to these two discussions:
ToolBar disappears when setting elevation for AppBarLayout
when set app:elevation="0dp" then hamburgermenu not showing to toolbar
Use android:stateListAnimator="#null". No side effect.
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:stateListAnimator="#null"
>
I tried app:elevation="0dp" but the toolbar desappear, but using app:elevation="0.1dp" made the trick.
Hope this helps somebody else.
Add app:elevation="0dp" on your AppBarLayout. like this example
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
Programmatically you can use this :
getSupportActionBar().setElevation(0.0f);
This is the way that I came up with app:elevation="0dp" to remove the shadow.Perfectly works.
I am doing this on Kotlin minSdkVersion 21 with AppBarLayout & TabLayout so: app:elevation="0dp" does indeed help me solve the shadow problem BUT using this solution make it so that I will not be able to press the button on the TabLayout.
so combine app:elevation="0.1dp" & app:elevation="0dp"i can fix the shadow and still be able to interact with my tab layout.

How does the Android L contacts app collapse its toolbar?

I've been trying to reproduce the way that the Contacts app on version 5.0 collapses the toolbar when the listview is scrolled.
Gallery of screenshots demonstrating the desired interaction
Note the collapse of the toolbar in stages, where it displays search+last contact, fades last contact, collapses last contact, collapses search, leaving only the tabs.
So far, I have a toolbar sitting above a recyclerview in a LinearLayout, and the toolbar is used as an actionbar, not standalone.
I can't figure out how to intercept the touch event on the recyclerview and make it shrink the toolbar, and then return the scroll event to the recyclerview. I tried putting the entire thing in a scrollview, but then the recyclerview couldn't calculate it's height properly and displayed no content. I tried overriding onscroll on the recyclerview, and found that it will only notify me when a scroll event started, and provide me with the first visible card id.
The way that looks right, but I can't get working for the life of me, is this:
getSupportActionBar().setHideOnContentScrollEnabled(true);
Which returns:
Caused by: java.lang.UnsupportedOperationException: Hide on content scroll is not supported in this action bar configuration.
Using a traditional actionbar, putting a toolbar below it, and setting hideoncontentscrollenabled also didn't work, scrolling never triggered the hide method on the actionbar.
-- edit --
I was able to get hideOnContentScrollEnabled working on a listview with a traditional actionbar, but the behavior is not the same as the contacts app. This is clearly not the method they used-- it simply triggers .hide() on the actionbar when a fling event occurs on a listview, which is notably different from the contacts app, which drags the toolbar along with the scroll event.
-- /edit --
So I abandoned that route, and put fill_parent on the cardview height, and animated a collapse on the toolbar. But how do I trigger it so that it follows the touch event and then returns the touch event to the recyclerview?
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="#color/colorPrimary"
/>
<fragment android:name="me.myapplication.FragmentTab"
android:id="#+id/tab_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
fragment_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="8dp"
android:background="#eeeeee"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
styles.xml
...
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
MainActivity.java
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
// Disable the logo in the actionbar, as per material guidelines
toolbar.getMenu().clear();
toolbar.setTitle("My toolbar");
setSupportActionBar(toolbar);
I haven't investigated the source code yet but this guy seems to have made life easy yet enlightening.
https://github.com/ksoichiro/Android-ObservableScrollView
EDIT
Google has just released Android Design Library. Please take a look as it contains all the effects of collapsing toolbars and much more.
Well, I have no idea how they do it, but... why don't you take a peek to the source code? Luckily for us, the Contacts app is still open-source on Android L (others weren't as lucky as Contacts, like Mail, which does not work anymore on L; or Keyboard, which they stopped updating anymore since the launch of their propietary Google Keyboard).
Anyway, here's the source code I think you should look at:
https://github.com/android/platform_packages_apps_contacts/blob/master/src%2Fcom%2Fandroid%2Fcontacts%2Factivities%2FActionBarAdapter.java
Note the method update(boolean skipAnimation) in Line 311, which calls animateTabHeightChange(int start, int end) (Line 437).
My guess is all the magic happens there ;-)
As of June 2015, your desired effect can be accomplished via the so called CollapsingToolbarLayout of the new design support library.
Based on the sample code here, I am figuring that:
the search cardview is child of the toolbar
the missed call cardview belongs to the collapsingtoolbar with the collapseMode attribute set to pin
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="112dp"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="?attr/actionBarSize"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="false"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways">
<!-- Search layout -->
<android.support.v7.widget.CardView
</android.support.v7.widget.CardView>
</android.support.v7.widget.Toolbar>
<!-- Last call card view-->
<android.support.v7.widget.CardView
app:layout_collapseMode="pin">
</android.support.v7.widget.CardView>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#color/primary_color"
app:layout_scrollFlags="scroll"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
No third party library is required now! Android is officially providing library. You can collapse the toolbar and do many other tweaks.
Check this android-developer's blog
And don't forget to add this dependency in your build.gradle file.
compile 'com.android.support:design:22.2.0'
I found this library that seems to do what you're looking for: https://github.com/kmshack/Android-ParallaxHeaderViewPager and this https://github.com/flavienlaurent/NotBoringActionBar
You can play the video to see the behavior: https://www.youtube.com/watch?v=sCP-b0a1x5Y
It might not be the 'new' standard way of doing it with ToolBar, but it might give you an idea by inspecting the code. It seems to attach a OnScrollListener to the scrolling content and then trigger changes on the size of the bar.
For me https://mzgreen.github.io/2015/06/23/How-to-hideshow-Toolbar-when-list-is-scrolling%28part3%29/ has helped. A source code is found here: https://github.com/mzgreen/HideOnScrollExample/tree/master/app/src/main.
A RecycleView in your layout should look like:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
Note that after starting an application 2 toolbars appear (actionbar and toolbar). So in your activity.java you should write so:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide ActionBar.
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(R.layout.your_activity_layout);
...
The toolbar is customized as shown here: https://stackoverflow.com/a/26548766/2914140. I mean, it appears without title and any other elements, so you can add them in a layout.
Android's Contact app doesn't have an easy plug-and-play solution that you can grab for use in your own app.
It does a full implementation, essentially doing it the same way you would do it if you were implementing it from scratch. For context, before looking at the code, keep in mind how the views are laid out:
https://github.com/android/platform_packages_apps_contacts/blob/lollipop-release/res/layout/quickcontact_activity.xml
The MultiShrinkScroller is a FrameLayout which intermediates the scrolling behavior, but the main stuff is in a LinearLayout, so reducing the height of the higher views will "scroll" the lower views upwards.
The key file for the implementation is this one:
https://github.com/android/platform_packages_apps_contacts/blob/lollipop-release/src/com/android/contacts/widget/MultiShrinkScroller.java
public void scrollTo(int x, int y) {
final int delta = y - getScroll();
boolean wasFullscreen = getScrollNeededToBeFullScreen() <= 0;
if (delta > 0) {
scrollUp(delta);
} else {
scrollDown(delta);
}
updatePhotoTintAndDropShadow();
updateHeaderTextSizeAndMargin();
//... other stuff
}
private void scrollUp(int delta) {
// Collapse higher views first
if (getTransparentViewHeight() != 0) {
final int originalValue = getTransparentViewHeight();
setTransparentViewHeight(getTransparentViewHeight() - delta);
setTransparentViewHeight(Math.max(0, getTransparentViewHeight()));
delta -= originalValue - getTransparentViewHeight();
}
// Shrink toolbar as needed
final ViewGroup.LayoutParams toolbarLayoutParams
= mToolbar.getLayoutParams();
if (toolbarLayoutParams.height > getFullyCompressedHeaderHeight()) {
final int originalValue = toolbarLayoutParams.height;
toolbarLayoutParams.height -= delta;
toolbarLayoutParams.height = Math.max(toolbarLayoutParams.height,
getFullyCompressedHeaderHeight());
mToolbar.setLayoutParams(toolbarLayoutParams);
delta -= originalValue - toolbarLayoutParams.height;
}
// Finally, scroll content if nothing left to shrink
mScrollView.scrollBy(0, delta);
}
updatePhotoTintAndDropShadow(); and updateHeaderTextSizeAndMargin(); handle the change in tint and text as it gets collapsed so that it turns into the look and feel of a regular ActionBar/ToolBar.
You could grab the MultiShrinkScroller file itself and adapt it for your own use, but there are probably easier implementations nowadays (including those from Android's design library).

Categories

Resources