CollapsingToolbarLayout subtitle
If you want the subtitle to go to Toolbar
when the AppBar
is fully collapsed you should create your custom CoordinatorLayout.Behaviour
Like this: Github Guide
But if you just want a smaller text behind the title when the AppBar
is expanded you can try this layout:
<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:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="300dp"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginBottom="160dp"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/quila2"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@android:color/white"
android:layout_marginBottom="32dp"
android:layout_marginEnd="64dp"
android:layout_marginStart="48dp"
app:layout_collapseMode="parallax"
android:layout_gravity="bottom"
android:text="Lorem Ipsum Iran Lorem Ipsum Iran Lorem Ipsum Iran Lorem Ipsum Iran Lorem Ipsum Iran Lorem Ipsum Iran Lorem Ipsum Iran Lorem Ipsum Iran "/>
<android.support.v7.widget.Toolbar
android:id="@+id/anim_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:lineSpacingExtra="8dp"
android:text="@string/lorem"
android:textSize="18sp"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:src="@drawable/abc_ic_search_api_mtrl_alpha"
app:layout_anchor="@+id/appbar"
app:layout_anchorGravity="bottom|right|end" />
</android.support.design.widget.CoordinatorLayout>
Notice that here I set the AppBar
height as 300dp
and the app:expandedTitleMarginBottom
is 160dp
so the title won't go down and conflict with the out subtitle. In this example you should set CollapsingToolbarTitle
dynamically in the runtime with collapsingToolbarTitle.setTitle("My Title");
method.
The result will be something like this:
Subtitle support in a CollapsingToolbarLayout
is a feature that I also long for, so I created a library collapsingtoolbarlayout-subtitle:
Use it like you would on any CollapsingToolbarLayout
, just add subtitle attribute on it:
<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.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.hendraanggrian.widget.SubtitleCollapsingToolbarLayout
android:id="@+id/subtitlecollapsingtoolbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="?colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:subtitle="CollapsingToolbarLayout"
app:title="Subtitle">
<!-- collapsing toolbar content goes here -->
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
app:layout_collapseMode="pin"/>
</com.hendraanggrian.widget.SubtitleCollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- content goes here -->
</android.support.design.widget.CoordinatorLayout>
Try something like this, it work for me I have created custom ViewBehavior
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, HeaderView child, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, HeaderView child, View dependency) {
shouldInitProperties(child, dependency);
int maxScroll = ((AppBarLayout) dependency).getTotalScrollRange();
float percentage = Math.abs(dependency.getY()) / (float) maxScroll;
float childPosition = dependency.getHeight()
+ dependency.getY()
- child.getHeight()
- (getToolbarHeight() - child.getHeight()) * percentage / 2;
childPosition = childPosition - mStartMarginBottom * (1f - percentage);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.leftMargin = (int) (percentage * mEndMargintLeft) + mStartMarginLeft;
lp.rightMargin = mMarginRight;
child.setLayoutParams(lp);
child.setY(childPosition);
...
return true;
}
and this my layout
<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:fitsSystemWindows="true"
>
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
>
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@drawable/img_nature"
app:layout_collapseMode="parallax"
/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
>
<include
android:id="@+id/toolbar_header_view"
layout="@layout/header_view"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginRight="@dimen/header_view_end_margin_right"
android:visibility="gone"
/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
...
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<include
android:id="@+id/float_header_view"
layout="@layout/header_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.subtitlebehavoir.harcopro.simple.ViewBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
ViewHeader layout:
<?xml version="1.0" encoding="utf-8"?>
<com.subtitlebehavoir.harcopro.simple.HeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<!-- Title -->
<TextView
android:id="@+id/header_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="18sp"
/>
<!-- Subtitle -->
<TextView
android:id="@+id/header_view_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="16sp"
/>
</com.subtitlebehavoir.harcopro.simple.HeaderView>
Here is the modified version of Harco's implmentation (this) given above which will also change the size of title as we expand and collapse the layout.
ViewBehavior.java
public class ViewBehavior extends CoordinatorLayout.Behavior<HeaderView> {
private static final float MAX_SCALE = 0.5f;
private Context mContext;
private int mStartMarginLeft;
private int mEndMargintLeft;
private int mMarginRight;
private int mStartMarginBottom;
private boolean isHide;
public ViewBehavior(Context context, AttributeSet attrs) {
mContext = context;
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, HeaderView child, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, HeaderView child, View dependency) {
shouldInitProperties(child, dependency);
int maxScroll = ((AppBarLayout) dependency).getTotalScrollRange();
float percentage = Math.abs(dependency.getY()) / (float) maxScroll;
// Set scale for the title
float size = ((1 - percentage) * MAX_SCALE) + 1;
child.setScaleXTitle(size);
child.setScaleYTitle(size);
// Set position for the header view
float childPosition = dependency.getHeight()
+ dependency.getY()
- child.getHeight()
- (getToolbarHeight() - child.getHeight()) * percentage / 2;
childPosition = childPosition - mStartMarginBottom * (1f - percentage);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.leftMargin = (int) (percentage * mEndMargintLeft) + mStartMarginLeft;
lp.rightMargin = mMarginRight;
child.setLayoutParams(lp);
child.setY(childPosition);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (isHide && percentage < 1) {
child.setVisibility(View.VISIBLE);
isHide = false;
} else if (!isHide && percentage == 1) {
child.setVisibility(View.GONE);
isHide = true;
}
}
return true;
}
private void shouldInitProperties(HeaderView child, View dependency) {
if (mStartMarginLeft == 0)
mStartMarginLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_start_margin_left);
if (mEndMargintLeft == 0)
mEndMargintLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_end_margin_left);
if (mStartMarginBottom == 0)
mStartMarginBottom = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_start_margin_bottom);
if (mMarginRight == 0)
mMarginRight = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_end_margin_right);
}
public int getToolbarHeight() {
int result = 0;
TypedValue tv = new TypedValue();
if (mContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
result = TypedValue.complexToDimensionPixelSize(tv.data, mContext.getResources().getDisplayMetrics());
}
return result;
}
}
HeaderView.java
public class HeaderView extends LinearLayout {
@Bind(R.id.header_view_title)
TextView title;
@Bind(R.id.header_view_sub_title)
TextView subTitle;
public HeaderView(Context context) {
super(context);
}
public HeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.bind(this);
}
public void bindTo(String title) {
bindTo(title, "");
}
public void bindTo(String title, String subTitle) {
hideOrSetText(this.title, title);
hideOrSetText(this.subTitle, subTitle);
}
private void hideOrSetText(TextView tv, String text) {
if (text == null || text.equals(""))
tv.setVisibility(GONE);
else
tv.setText(text);
}
public void setScaleXTitle(float scaleXTitle) {
title.setScaleX(scaleXTitle);
title.setPivotX(0);
}
public void setScaleYTitle(float scaleYTitle) {
title.setScaleY(scaleYTitle);
title.setPivotY(30);
}
}
I also had the same issue. In the end I made a LinearLayout that contains the title and subtitle and then set the expandedTitleTextAppearance to be transparent - effectively hiding the Toolbar title when the Layout is expanded. Using this approach the toolbar collapses over the LinearLayout and in the end only shows the title in the collapsed state.
The full xml is here:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/series_detail_header_height"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:expandedTitleTextAppearance="@style/TransparentText"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_collapseMode="parallax">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="@dimen/series_detail_header_image_height"
android:scaleType="centerCrop"/>
<LinearLayout
android:id="@+id/header_text_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?attr/colorPrimary"
android:gravity="center_vertical"
android:minHeight="@dimen/series_detail_text_layout_height"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="10dp"
android:paddingTop="10dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="My title"
android:textColor="@android:color/white"
android:textSize="24sp"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="17sp"/>
</LinearLayout>
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@drawable/shape_toolbar_black_gradient"
app:layout_collapseMode="pin"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="top"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/show_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:paddingTop="@dimen/toolbar_height"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/></android.support.design.widget.CoordinatorLayout>
Make sure that your style also extends TextAppearance or the app will crash if your Design Support Library is v22.2.0 :
<style name="TransparentText" parent="@android:style/TextAppearance">
<item name="android:textColor">#00666666</item>
</style>
This bug appears to be fixed in v22.2.1 (https://code.google.com/p/android/issues/detail?id=178674):