Android CollapsingToolbarLayout with custom View
Solution 1
I had the same problem and spend many hours trying to find a solution. My solution was to add the collapsing Views (ImageView and TextView) inside the CollapsingToolbarLayout
and then handle the transition in code. This way it's more flexible and simpler than extending from CollapsingToolbarLayout.
First you'll need to add your Views inside the CollapsingToolbarLayout
with the parallax properties:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="@drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
Then set the scaling of the Views with the help of an OnOffsetchangeListner
:
private static final float SCALE_MINIMUM=0.5f;
appBarLayout.setOnWorkingOffsetChange(new ControllableAppBarLayout.OnWorkingOffsetChange() {
@Override
public void onOffsetChange(int offSet, float collapseDistance) {
imageView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
imageView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
Somehow the default offsetChangedListener
didn't work properly for me (you probably still should try it with the default listener first), so I used the ControllableAppBarLayout
from https://gist.github.com/blipinsk/3f8fb37209de6d3eea99 and added the following:
private OnWorkingOffsetChange onWorkingOffsetChange;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (!isInEditMode()) {
onWorkingOffsetChange.onOffsetChange(i, (float) i / appBarLayout.getTotalScrollRange());
}
}
public void setOnWorkingOffsetChange(OnWorkingOffsetChange listener) {
this.onWorkingOffsetChange = listener;
}
public interface OnWorkingOffsetChange {
void onOffsetChange(int offSet, float collapseDistance);
}
The only problem is, that you would need to set
app:contentScrim="#00000000"
(transparent)
for your CollapsingToolbarLayout
, so your views are still visible when the toolbar is collapsed. If you really need the collapsing-background effect I'm sure you could "fake" this by setting the alpha of a background ImageView in the OffsetChangeListener
. ;)
Solution 2
Going to edit Christopher's answer slightly to show how you can get your custom view to not disappear on collapse:
First you'll need to add your Views inside the CollapsingToolbarLayout
with the parallax properties:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="@drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
Instead add the custom view's programmatically and it won't disappear on collapse. For example here is a view that contains a title and a subtitle:
final FrameLayout frameLayout = new FrameLayout(mActivity);
FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
frameLayout.setLayoutParams(frameLayoutParams);
// Create new LinearLayout
final LinearLayout linearLayout = new LinearLayout(mActivity);
frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
linearLayout.setLayoutParams(frameLayoutParams);
linearLayout.setOrientation(LinearLayout.VERTICAL);
// Add textviews
final TextView textView1 = new TextView(mActivity);
LinearLayout.LayoutParams linearLayoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
frameLayoutParams.gravity = Gravity.BOTTOM;
textView1.setLayoutParams(linearLayoutParams);
textView1.setText("Title");
textView1.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
linearLayout.addView(textView1);
final TextView textView2 = new TextView(mActivity);
linearLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textView2.setLayoutParams(linearLayoutParams);
textView2.setText("Subtitle");
textView2.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
linearLayout.addView(textView2);
frameLayout.addView(linearLayout);
collapsingToolbar.addView(frameLayout);
final float SCALE_MIN=0.4f;
AppBarLayout appBarLayout = (AppBarLayout) mActivity.findViewById(R.id.appBarLayout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offSet) {
float collapsedRatio = (float) offSet / appBarLayout.getTotalScrollRange();
linearLayout.setScaleX(1 + (collapsedRatio * SCALE_MIN));
linearLayout.setScaleY(1 + (collapsedRatio * SCALE_MIN));
FrameLayout.LayoutParams frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
frameLayoutParams.setMargins(Math.round(dpToPixels(48) * (1+collapsedRatio)), 0, 0, Math.round(dpToPixels(15) * collapsedRatio));
linearLayout.setLayoutParams(frameLayoutParams);
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
/////
float lastCollapsedRatio = -2;
////
private int dpToPixels(int padding_in_dp){
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
return padding_in_px;
}
Solution 3
From the widget itself there doesn't seem to be a way to enable this directly, like it was possible to add custom views to the Toolbar.
What you could try to do however, is open the source of the CollapsingToolbarLayout.class
and check out how the CollapsingTextHelper.class
is used to have the title set. You could try to make your own widget by extending from the the CollapsingToolbarLayout
.
These links can help you out with creating custom components/views, if you haven't created them before: Custom Views, Custom Components
I haven't tried this yet, but it's actually something I was thinking about trying to achieve a similar solution as you are looking for. Steps I tihkn I would follow, so far:
- Create custom attributes for subtitle settings in
attrs.xml
- Create your own
MyCollapsingToolbarLayout
by extending the original one. - Make sure to call
super
in the constructors, so the original component will stay intact. - Create a
subtitleTextHelper
by adding a newCollapsingTextHelper
to your component. - Override
onDraw
to actually draw your subtitle. - Update the layout containing your
CollapingsToolbarLayout
with your subtitle attributes (default styling and such, maybe a fixed subtitle Text). - Apply the changes in the
Activity
containing yourCollapsingToolbar
. (ConvertCollapsingToolbarlayout
toMyCollapingsToolbarLayout
, set subtitles, extra custom settings, etc). - Cross fingers, test.
Going to have a look at it now.
Related videos on Youtube
Comments
-
CeccoCQ almost 2 years
I'm following the Cheesesquare example project to understand the new design material library.
I'm wondering if there's a way to use a custom view (like Telegram) with ImageView, title and subtitle instead of the simple Title provided by CollapsingToolbarLayout widget.
Thanks.
-
shkschneider almost 9 yearsHave you tried a
CollapsingToolbarLayout
containing anImageView
first and then aLinearLayout
with 2TextView
s? -
CeccoCQ almost 9 yearsI've tried, but my purpose is the replacement the Title with my CustomView to preserve the animation of the title in the toolbar.
-
Devendra Singh over 7 years@shkschneider would you explain a bit more. i want to use
-
-
CeccoCQ almost 9 yearsIt was a really hard work. CollapsingToolbarLayout is a terrible widget.
-
Max almost 9 years@StingRay5 Can you help me what to do inside onDraw()? Or please share your code.
-
Devendra Singh over 7 yearswould you please explain a bit more. i have the same problem, i just want to use an icon and a title in the centre of
CollapsingToolBarLayout
when i scroll up than the icon must fly to toolbar's left side where normally the app icon exists and the title is in the right side of icon. -
Roy Solberg over 7 yearsGreat trick. Except that I suddenly got my logs filled with the following. Any ideas on how to avoid that? (Gah, why can't SO comments support line breaks?)
requestLayout() improperly called by android.support.design.widget.CollapsingToolbarLayout{a9c7244 V.ED..... ......I. 0,0-1440,405 #7f1100fb app:id/collapsingToolbarLayout} during layout: running second layout pass
requestLayout() improperly called by android.widget.LinearLayout{4058f2d V.E...... ......I. 168,132-1440,405} during layout: running second layout pass
-
Roy Solberg over 7 yearsI added a check to see if
collapsedRatio
actually has changed and only do the scaling in those cases. That made all the complaining about second layout pass disappear. -
luca992 over 7 yearsI haven't used this code in a while. But I do remember encountering that. Where did you add the check? I can update my answer. @RoySolberg