I am trying to make something like this.where each item has equal width and height.I set the width to match_parent and change the height dynamically inside onBindView()
here is what I did so far.I tried to get the width of the cardView (which is the container of the item) inside the onBindView and assign it to height.
but it always gives -1 when logging
activity.java
private void setupRecyclerView() {
categoryRecyclerAdapter = new CategoryRecyclerAdapter(this);
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this, 2);
categoryRecyclerView.setLayoutManager(layoutManager);
categoryRecyclerView.setAdapter(categoryRecyclerAdapter);
RecyclerView.ItemDecoration itemDecoration = new ItemDecorationCategory(5, 2);
categoryRecyclerView.addItemDecoration(itemDecoration);
}
adapter.java
#Override
public void onBindViewHolder(CategoryViewHolder holder, int position) {
Category category = categoryList.get(position);
int width = holder.cardViewContainer.getMeasuredWidth(); //returns -1
holder.cardViewContainer.getLayoutParams().height = width;
Timber.d("width --> " + width);
holder.cardViewContainer.requestLayout();
holder.textViewCat.setText(category.getCategory());
Picasso.with(context).load(category.getResId()).into(holder.imageViewCat);
}
public class CategoryViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.cardViewContainer)
CardView cardViewContainer;
#BindView(R.id.cat_imageView)
ImageView imageViewCat;
#BindView(R.id.cat_textView)
TextView textViewCat;
public CategoryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
activity.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey"
tools:context="com.project.bishoy.lost.category.CategoryActivity">
<android.support.v7.widget.RecyclerView
tools:listitem="#layout/category_item"
android:id="#+id/category_recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
item.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardViewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
app:cardCornerRadius="5dp"
app:elevation="5dp">
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
tools:layout_editor_absoluteY="25dp">
<ImageView
android:id="#+id/cat_imageView"
android:layout_width="72dp"
android:layout_height="72dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/main_background" />
<TextView
android:id="#+id/cat_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:text="#string/mob"
android:textColor="#color/black"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/cat_imageView"
app:layout_constraintVertical_bias="0.241" />
</android.support.constraint.ConstraintLayout>
I tried this, but it doesn't help
I have a very simple scenario involving a NestedScrollView and LinearLayout where I want the LinearLayout to translate as the NestedScrollView scrolls up. Here is the layout in picture:(the concerned child view is the second last LinearLayout with the Id of linearlayout )
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.snapsboardmainpage.MainActivity"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp">
<android.support.v4.widget.NestedScrollView
android:id="#+id/nested_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="vertical"
android:layout_gravity="top"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="0dp"
android:layout_marginRight="0dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="0dp"
app:layout_constraintLeft_toLeftOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="0dp"
android:layout_height="112dp"
android:orientation="vertical"
android:background="#android:color/holo_green_light"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/linearLayout3">
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="#+id/id_viewpager_photosvideos_albums"
android:layout_width="0dp"
android:layout_height="1000dp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout1">
<android.support.design.widget.TabLayout
android:id="#+id/id_tab_photosvideos_albums"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top">
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.design.widget.TabLayout>
</android.support.v4.view.ViewPager>
</android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="vertical"
android:layout_gravity="top"
app:layout_behavior="com.example.snaps.TopActionBarBehavior"
android:background="#android:color/holo_blue_light">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="vertical"
android:layout_gravity="bottom"
android:background="#android:color/holo_orange_light">
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
And, the concerned behavior(TopActionBarBehavior) as follows:
public class TopActionBarBehavior extends CoordinatorLayout.Behavior<LinearLayout> {
private static final String TAG = "TopActionBarBehavior";
private int thresholdScrollDistance;
private int mNestedScrollViewInitialTop;
public TopActionBarBehavior() {
}
public TopActionBarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, LinearLayout child, View dependency) {
return dependency instanceof NestedScrollView;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, LinearLayout child, View dependency) {
// Translate the child view as per the NestedScrollView
int currentNestedScrollViewTop = dependency.getTop();
// Have we scrolled up?
if(currentNestedScrollViewTop > mNestedScrollViewInitialTop){
// Translate the child view by the same distance
child.setTranslationY(currentNestedScrollViewTop - mNestedScrollViewInitialTop);
}
return true;
}
#Override
public boolean onLayoutChild(CoordinatorLayout parent, LinearLayout child, int layoutDirection) {
View topBar = parent.findViewById(R.id.linearLayout);
int topBarHeight = topBar.getHeight();
View nestedScrollView = parent.findViewById(R.id.nested_container);
mNestedScrollViewInitialTop = nestedScrollView.getTop();
View profileBar = parent.findViewById(R.id.linearLayout1);
int profileBarHeight = profileBar.getHeight();
View dummyTopBarUnderlay = parent.findViewById(R.id.linearLayout3);
int dummyTopBarHeight = dummyTopBarUnderlay.getHeight();
View tabLayout = parent.findViewById(R.id.id_tab_photosvideos_albums);
int tabLayoutHeight = tabLayout.getHeight();
thresholdScrollDistance = profileBarHeight + dummyTopBarHeight + tabLayoutHeight;
return super.onLayoutChild(parent, child, layoutDirection);
}
}
I tried debugging and layoutDependsOn() is getting called as it should be but onDependentViewChanged() is getting called only once.
Finally found the answer after countless hours of debugging. My NestedScrollView wasn't actually moving at all; it's content was moving the whole time which didn't trigger this method. For scroll events, we can tap onto the onNested*() methods in the Behavior class. Simple.
This is the screenshot of one of my fragments (device: Xiaomi Redmi 2)
The fragment is divided into 4 parts:
A ViewPager to display image ads
A ViewPager indicator
A RecyclerView which contains a bunch of CardViews (to display news)
An AHBottomNavigation
And this is its corresponding XML layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:orientation="vertical"
android:weightSum="1.5">
<!-- for displaying ads -->
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0" />
<LinearLayout
android:id="#+id/llDots"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_weight="0.5"
android:gravity="center"
android:background="#android:color/black"
android:orientation="horizontal" />
</LinearLayout>
<!-- for displaying news -->
<android.support.v7.widget.RecyclerView
android:id="#+id/news_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.5" />
<!-- bottom navigation -->
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
I think the height of the ViewPager Indicator and the AHBottomView is right. But the ViewPager height is too much. What I want is the height of the ViewPager to fit the height of the image ads, and the height of the RecyclerView is bigger. I tried reducing the value weightSum (of the top LinearLayout) from 3 to 2.5, turns out the the AHbottomNavigation is not visible anymore.
Change like below
1. Replace xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
>
<!-- for displaying ads -->
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<LinearLayout
android:id="#+id/llDots"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:background="#android:color/black"
android:orientation="horizontal" />
<!-- for displaying news -->
<android.support.v7.widget.RecyclerView
android:id="#+id/news_list"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
/>
</LinearLayout>
<!-- bottom navigation -->
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
2.change view pager with wrap content
You can use the below code.
public class WrapContentViewPager extends ViewPager {
private int mCurrentPagePosition = 0;
public WrapContentViewPager(Context context) {
super(context);
}
public WrapContentViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
View child = getChildAt(mCurrentPagePosition);
if (child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
}
} catch (Exception e) {
e.printStackTrace();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void reMeasureCurrentPage(int position) {
mCurrentPagePosition = position;
requestLayout();
}
}
Declare it in xml:
<your.package.name.WrapContentViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</your.package.name.WrapContentViewPager>
And call reMeasureCurrentpage function on page swipe.
final WrapContentViewPager wrapContentViewPager = (WrapContentViewPager) findViewById(R.id.view_pager);
wrapContentViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
wrapContentViewPager.reMeasureCurrentPage(wrapContentViewPager.getCurrentItem());
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
happy coding :)
I'm facing a strange problem. I have a xml with two RecyclerView and a ViewPager with circle page indicator inside a NestedScrollview. I have used layout_weight and weightSum to show widget on screen. One of RecyclerView has horizontal layout which is scrolling horizontally fine. I want to achieve single vertical scrolling but unfortunately it is not working.
I have used "app:layout_behavior="#string/appbar_scrolling_view_behavior" in xml and "recyclerview.setNestedScrollingEnabled(false)" in java code.
here is my fragment_home.xml
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.e2e.qnamo.fragment.HomeFragment">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="10"
android:descendantFocusability="blocksDescendants">
<include
layout="#layout/layout_pager_indicator"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_hot_topic"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="20dp"
android:layout_weight="2"
tools:listitem="#layout/hot_topic_row" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_category"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="20dp"
android:layout_weight="5"
tools:listitem="#layout/category_row"/>
</LinearLayout>
here is my layout_pager_indicator.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="#+id/bannerViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="#layout/viewpager_indicator_single_item" />
<com.e2e.qnamo.widget.CirclePageIndicator
android:id="#+id/pager_indicator"
style="#style/CustomCirclePageIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="center|bottom"/>
Seems like every one was busy else where :) Anyway I managed to find solution by myself.
There were three potential problem which causing problem:
Using "weightSum" in parent layout and
ViewPager in layout
ViewPager takes whole screen by default.
I have used "weightSum" to control size of ViewPager and showing other two Recyclerview. To remove "weightSum" I customised ViewPager so that it only takes height of its biggest children. Below are the customised ViewPager code:
public class CustomViewPager extends ViewPager
{
private int mCurrentPagePosition = 0;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for(int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if(h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void reMeasureCurrentPage(int position) {
mCurrentPagePosition = position;
requestLayout();
}
}
Second step I did that I removed "layout_weight" from both of RecyclerView and set it "layout_height" to "wrap_content" and work done.
Below are the updated layout code:
fragment_home.xml
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:fillViewport="true"
tools:context="com.e2e.qnamo.fragment.HomeFragment">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="#dimen/main_container_margin"
android:layout_marginTop="#dimen/main_container_margin"
android:layout_marginRight="#dimen/main_container_margin"
android:layout_marginBottom="#dimen/main_container_margin"
android:orientation="vertical">
<include
layout="#layout/layout_pager_indicator"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_hot_topic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/recycler_margin_top"
tools:listitem="#layout/hot_topic_row" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_category"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/recycler_margin_top"
android:layout_marginBottom="10dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:listitem="#layout/category_row"/>
</LinearLayout>
layout_pager_indicator.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.e2e.qnamo.widget.CustomViewPager
android:id="#+id/bannerViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="#layout/viewpager_indicator_single_item" />
<com.e2e.qnamo.widget.CirclePageIndicator
android:id="#+id/pager_indicator"
style="#style/CustomCirclePageIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="center|bottom"/>
Thats it!!!
Am I able to set the title of a CollapsingToolbarLayout via the setTitle method?
Is there also a way to set a 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):
Here is the modified version of Harco's implementation (this) with title and subtitle centred when expanded.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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_width="wrap_content"
android:layout_height="wrap_content"
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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<include
android:id="#+id/float_header_view"
layout="#layout/header_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="com.subtitlebehavoir.harcopro.simple.ViewBehavior" />
</android.support.design.widget.CoordinatorLayout>
dimens.xml
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="header_view_end_margin_left">56dp</dimen>
<dimen name="header_view_end_margin_right">14dp</dimen>
<dimen name="header_view_start_margin_bottom">14dp</dimen>
</resources>
header_view.xml
<?xml version="1.0" encoding="utf-8"?>
<com.subtitlebehavoir.harcopro.simple.HeaderView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- Title -->
<TextView
android:id="#+id/header_view_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:textColor="#android:color/white"
android:textSize="18sp" />
<!-- Subtitle -->
<TextView
android:id="#+id/header_view_sub_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/header_view_title"
android:maxLines="1"
android:textColor="#android:color/white"
android:textSize="16sp" />
</com.subtitlebehavoir.harcopro.simple.HeaderView>
HeaderView.java
public class HeaderView extends RelativeLayout {
#Bind(R.id.header_view_title)
TextView title;
#Bind(R.id.header_view_sub_title)
TextView subTitle;
Context context;
public HeaderView(Context context) {
super(context);
this.context = context;
}
public HeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.context = context;
}
#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);
}
public TextView getTitle() {
return title;
}
public TextView getSubTitle() {
return subTitle;
}
}
and ViewBehavior.java
public class ViewBehavior extends CoordinatorLayout.Behavior<HeaderView> {
private static final float MAX_SCALE = 0.5f;
private Context mContext;
private int mStartMarginLeftTitle;
private int mStartMarginLeftSubTitle;
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);
child.setY(childPosition);
// Set Margin for title
RelativeLayout.LayoutParams lpTitle = (RelativeLayout.LayoutParams) child.getTitle().getLayoutParams();
lpTitle.leftMargin = (int) ((mStartMarginLeftTitle) - (percentage * (mStartMarginLeftTitle - mEndMargintLeft)));
if (lpTitle.leftMargin < 20) {
lpTitle.leftMargin = 20;
}
lpTitle.rightMargin = mMarginRight;
child.getTitle().setLayoutParams(lpTitle);
// Set Margin for subtitle
RelativeLayout.LayoutParams lpSubTitle = (RelativeLayout.LayoutParams) child.getSubTitle().getLayoutParams();
lpSubTitle.leftMargin = (int) ((mStartMarginLeftSubTitle) - (percentage * (mStartMarginLeftSubTitle - mEndMargintLeft)));
if (lpSubTitle.leftMargin < 20) {
lpSubTitle.leftMargin = 20;
}
lpSubTitle.rightMargin = mMarginRight;
child.getSubTitle().setLayoutParams(lpSubTitle);
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 (mStartMarginLeftTitle == 0)
mStartMarginLeftTitle = getStartMarginLeftTitle(child);
if (mStartMarginLeftSubTitle == 0)
mStartMarginLeftSubTitle = getStartMarginLeftSubTitle(child);
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 getStartMarginLeftTitle(HeaderView headerView) {
TextView title = headerView.getTitle();
DisplayMetrics displaymetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int stringWidth = getStingWidth(title);
int marginLeft = (int) ((width / 2) - ((stringWidth + (stringWidth * MAX_SCALE)) / 2));
return marginLeft;
}
public int getStartMarginLeftSubTitle(HeaderView headerView) {
TextView subTitle = headerView.getSubTitle();
DisplayMetrics displaymetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int stringWidth = getStingWidth(subTitle);
int marginLeft = ((width / 2) - (stringWidth / 2));
return marginLeft;
}
public int getStingWidth(TextView textView) {
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(textView.getText().toString(), 0, textView.getText().toString().length(), bounds);
return bounds.width();
}
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;
}
}
i managed to make it using MotionLayout in your activity.xml make the following
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/motion_scene_collapsing_toolbar_with_subtitle"
tools:context=".CollapsingToolbarWithSubtitleActivity">
<ImageView
android:id="#+id/toolbar_image_expanded"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="?attr/colorPrimary"
android:contentDescription="#null"
android:scaleType="centerCrop"
android:src="#drawable/img1" />
<!-- transformPivotX and transformPivotY is to move text horizontal
or vertical in it's own boundaries when the text is smaller than it's boundaries-->
<TextView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is title"
android:textColor="#color/white"
android:textSize="30sp"
android:transformPivotX="0sp"
android:transformPivotY="25sp" />
<TextView
android:id="#+id/toolbar_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:text="This is sub title"
android:textColor="#color/white"
android:textSize="20sp"
android:transformPivotX="6sp"
android:transformPivotY="0sp" />
<!-- you can put any thing here ex (RecyclerView or Image or .... any thing).-->
<TextView
android:id="#+id/tv_remaining_body"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:text="remaining body what ever it is"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar_image_expanded" />
</androidx.constraintlayout.motion.widget.MotionLayout>
and then for #xml/motion_scene_collapsing_toolbar_with_subtitle add the following
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet android:id="#+id/expanded">
<Constraint
android:id="#+id/toolbar_image_expanded"
android:layout_height="200dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="imageAlpha"
app:customIntegerValue="255" />
</Constraint>
<Constraint
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="42dp"
android:scaleX="1.0"
android:scaleY="1.0"
app:layout_constraintBottom_toBottomOf="#+id/toolbar_image_expanded"
app:layout_constraintStart_toStartOf="parent" />
<Constraint
android:id="#+id/toolbar_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="1.0"
android:scaleY="1.0"
app:layout_constraintStart_toStartOf="#+id/toolbar_title"
app:layout_constraintTop_toBottomOf="#+id/toolbar_title" />
</ConstraintSet>
<ConstraintSet android:id="#+id/collapsed">
<Constraint
android:id="#+id/toolbar_image_expanded"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="imageAlpha"
app:customIntegerValue="0" />
</Constraint>
<Constraint
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginBottom="0dp"
android:scaleX="0.7"
android:scaleY="0.7"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/toolbar_image_expanded" />
<Constraint
android:id="#+id/toolbar_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="0.7"
android:scaleY="0.7"
app:layout_constraintBottom_toBottomOf="#id/toolbar_image_expanded"
app:layout_constraintStart_toStartOf="#id/toolbar_title"
app:layout_constraintTop_toBottomOf="#+id/toolbar_title" />
</ConstraintSet>
<Transition
app:constraintSetEnd="#id/collapsed"
app:constraintSetStart="#id/expanded">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="#id/tv_remaining_body"
app:touchAnchorSide="top" />
</Transition>
</MotionScene>
and if you want to know more about MotionLayout
visit this https://codelabs.developers.google.com/codelabs/motion-layout/#0