Comments (22)
On support library version 280.0 its not working i check it both to set 27.1.1 and 28.0.0
from collapsingtoolbarlayout-subtitle.
As far as I can remember, one of the last legacy artifact released is 27.1.1 com.hendraanggrian:collapsingtoolbaryout-subttitle:27.1.1
. Please describe more about the error.
from collapsingtoolbarlayout-subtitle.
My Support Library version in 28.0.0 and subtitle collapsing toolbar is 27.1.1 i got an error after app compiled,
PID: 12226
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: android.view.InflateException: Binary XML file line #21: Binary XML file line #21: Error inflating class android.support.design.widget.SubtitleCollapsingToolbarLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
from collapsingtoolbarlayout-subtitle.
You have to use matching support/AndroidX version as collapsingtoolbarlayout-subtitle
version. Unfortunately, I did not release legacy support version 28.0.0, you have to adopt AndroidX and use newer artifact com.hendraanggrian.material:collapsingtoolbarlayout-subtitle: 28.0.0
.
See demo app for example.
from collapsingtoolbarlayout-subtitle.
I am facing the same issue, AndroidX is still not production ready, I can't use AndroidX as of yet but migrated my app to 28.0.0 Support Library version
from collapsingtoolbarlayout-subtitle.
I am considering adding support to support library 28. Will update when I have more information.
from collapsingtoolbarlayout-subtitle.
Any update on release to support library 28?
from collapsingtoolbarlayout-subtitle.
Any updates?
from collapsingtoolbarlayout-subtitle.
Any update on this ?
from collapsingtoolbarlayout-subtitle.
Here's an update: progress is delayed because I can't seem to find design
source code in latest support library. And I have no way of mirroring how the actual collapsing toolbar layout works if I have no access to the source code.
If anyone can successfully locate the source of CollapsingTextHelper
and CollapsingToolbarLayout
in Support library 28.0.0, that could be a real time saver.
from collapsingtoolbarlayout-subtitle.
Hi @hendraanggrian
Source code for CollapsingTextHelper
`package android.support.design.widget;
import android.animation.TimeInterpolator;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.Bitmap.Config;
import android.os.Build.VERSION;
import android.support.annotation.ColorInt;
import android.support.annotation.RestrictTo;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.RestrictTo.Scope;
import android.support.design.animation.AnimationUtils;
import android.support.v4.math.MathUtils;
import android.support.v4.text.TextDirectionHeuristicsCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R.styleable;
import android.support.v7.widget.TintTypedArray;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.view.View;
@RestrictTo({Scope.LIBRARY_GROUP})
public final class CollapsingTextHelper {
private static final boolean USE_SCALING_TEXTURE;
private static final boolean DEBUG_DRAW = false;
private static final Paint DEBUG_DRAW_PAINT;
private final View view;
private boolean drawTitle;
private float expandedFraction;
private final Rect expandedBounds;
private final Rect collapsedBounds;
private final RectF currentBounds;
private int expandedTextGravity = 16;
private int collapsedTextGravity = 16;
private float expandedTextSize = 15.0F;
private float collapsedTextSize = 15.0F;
private ColorStateList expandedTextColor;
private ColorStateList collapsedTextColor;
private float expandedDrawY;
private float collapsedDrawY;
private float expandedDrawX;
private float collapsedDrawX;
private float currentDrawX;
private float currentDrawY;
private Typeface collapsedTypeface;
private Typeface expandedTypeface;
private Typeface currentTypeface;
private CharSequence text;
private CharSequence textToDraw;
private boolean isRtl;
private boolean useTexture;
private Bitmap expandedTitleTexture;
private Paint texturePaint;
private float textureAscent;
private float textureDescent;
private float scale;
private float currentTextSize;
private int[] state;
private boolean boundsChanged;
private final TextPaint textPaint;
private final TextPaint tmpPaint;
private TimeInterpolator positionInterpolator;
private TimeInterpolator textSizeInterpolator;
private float collapsedShadowRadius;
private float collapsedShadowDx;
private float collapsedShadowDy;
private int collapsedShadowColor;
private float expandedShadowRadius;
private float expandedShadowDx;
private float expandedShadowDy;
private int expandedShadowColor;
public CollapsingTextHelper(View view) {
this.view = view;
this.textPaint = new TextPaint(129);
this.tmpPaint = new TextPaint(this.textPaint);
this.collapsedBounds = new Rect();
this.expandedBounds = new Rect();
this.currentBounds = new RectF();
}
public void setTextSizeInterpolator(TimeInterpolator interpolator) {
this.textSizeInterpolator = interpolator;
this.recalculate();
}
public void setPositionInterpolator(TimeInterpolator interpolator) {
this.positionInterpolator = interpolator;
this.recalculate();
}
public void setExpandedTextSize(float textSize) {
if (this.expandedTextSize != textSize) {
this.expandedTextSize = textSize;
this.recalculate();
}
}
public void setCollapsedTextSize(float textSize) {
if (this.collapsedTextSize != textSize) {
this.collapsedTextSize = textSize;
this.recalculate();
}
}
public void setCollapsedTextColor(ColorStateList textColor) {
if (this.collapsedTextColor != textColor) {
this.collapsedTextColor = textColor;
this.recalculate();
}
}
public void setExpandedTextColor(ColorStateList textColor) {
if (this.expandedTextColor != textColor) {
this.expandedTextColor = textColor;
this.recalculate();
}
}
public void setExpandedBounds(int left, int top, int right, int bottom) {
if (!rectEquals(this.expandedBounds, left, top, right, bottom)) {
this.expandedBounds.set(left, top, right, bottom);
this.boundsChanged = true;
this.onBoundsChanged();
}
}
public void setCollapsedBounds(int left, int top, int right, int bottom) {
if (!rectEquals(this.collapsedBounds, left, top, right, bottom)) {
this.collapsedBounds.set(left, top, right, bottom);
this.boundsChanged = true;
this.onBoundsChanged();
}
}
public float calculateCollapsedTextWidth() {
if (this.text == null) {
return 0.0F;
} else {
this.getTextPaintCollapsed(this.tmpPaint);
return this.tmpPaint.measureText(this.text, 0, this.text.length());
}
}
public float getCollapsedTextHeight() {
this.getTextPaintCollapsed(this.tmpPaint);
return -this.tmpPaint.ascent();
}
public void getCollapsedTextActualBounds(RectF bounds) {
boolean isRtl = this.calculateIsRtl(this.text);
bounds.left = !isRtl ? (float)this.collapsedBounds.left : (float)this.collapsedBounds.right - this.calculateCollapsedTextWidth();
bounds.top = (float)this.collapsedBounds.top;
bounds.right = !isRtl ? bounds.left + this.calculateCollapsedTextWidth() : (float)this.collapsedBounds.right;
bounds.bottom = (float)this.collapsedBounds.top + this.getCollapsedTextHeight();
}
private void getTextPaintCollapsed(TextPaint textPaint) {
textPaint.setTextSize(this.collapsedTextSize);
textPaint.setTypeface(this.collapsedTypeface);
}
void onBoundsChanged() {
this.drawTitle = this.collapsedBounds.width() > 0 && this.collapsedBounds.height() > 0 && this.expandedBounds.width() > 0 && this.expandedBounds.height() > 0;
}
public void setExpandedTextGravity(int gravity) {
if (this.expandedTextGravity != gravity) {
this.expandedTextGravity = gravity;
this.recalculate();
}
}
public int getExpandedTextGravity() {
return this.expandedTextGravity;
}
public void setCollapsedTextGravity(int gravity) {
if (this.collapsedTextGravity != gravity) {
this.collapsedTextGravity = gravity;
this.recalculate();
}
}
public int getCollapsedTextGravity() {
return this.collapsedTextGravity;
}
public void setCollapsedTextAppearance(int resId) {
TintTypedArray a = TintTypedArray.obtainStyledAttributes(this.view.getContext(), resId, styleable.TextAppearance);
if (a.hasValue(styleable.TextAppearance_android_textColor)) {
this.collapsedTextColor = a.getColorStateList(styleable.TextAppearance_android_textColor);
}
if (a.hasValue(styleable.TextAppearance_android_textSize)) {
this.collapsedTextSize = (float)a.getDimensionPixelSize(styleable.TextAppearance_android_textSize, (int)this.collapsedTextSize);
}
this.collapsedShadowColor = a.getInt(styleable.TextAppearance_android_shadowColor, 0);
this.collapsedShadowDx = a.getFloat(styleable.TextAppearance_android_shadowDx, 0.0F);
this.collapsedShadowDy = a.getFloat(styleable.TextAppearance_android_shadowDy, 0.0F);
this.collapsedShadowRadius = a.getFloat(styleable.TextAppearance_android_shadowRadius, 0.0F);
a.recycle();
if (VERSION.SDK_INT >= 16) {
this.collapsedTypeface = this.readFontFamilyTypeface(resId);
}
this.recalculate();
}
public void setExpandedTextAppearance(int resId) {
TintTypedArray a = TintTypedArray.obtainStyledAttributes(this.view.getContext(), resId, styleable.TextAppearance);
if (a.hasValue(styleable.TextAppearance_android_textColor)) {
this.expandedTextColor = a.getColorStateList(styleable.TextAppearance_android_textColor);
}
if (a.hasValue(styleable.TextAppearance_android_textSize)) {
this.expandedTextSize = (float)a.getDimensionPixelSize(styleable.TextAppearance_android_textSize, (int)this.expandedTextSize);
}
this.expandedShadowColor = a.getInt(styleable.TextAppearance_android_shadowColor, 0);
this.expandedShadowDx = a.getFloat(styleable.TextAppearance_android_shadowDx, 0.0F);
this.expandedShadowDy = a.getFloat(styleable.TextAppearance_android_shadowDy, 0.0F);
this.expandedShadowRadius = a.getFloat(styleable.TextAppearance_android_shadowRadius, 0.0F);
a.recycle();
if (VERSION.SDK_INT >= 16) {
this.expandedTypeface = this.readFontFamilyTypeface(resId);
}
this.recalculate();
}
private Typeface readFontFamilyTypeface(int resId) {
TypedArray a = this.view.getContext().obtainStyledAttributes(resId, new int[]{16843692});
try {
String family = a.getString(0);
if (family != null) {
Typeface var4 = Typeface.create(family, 0);
return var4;
}
} finally {
a.recycle();
}
return null;
}
public void setCollapsedTypeface(Typeface typeface) {
if (this.collapsedTypeface != typeface) {
this.collapsedTypeface = typeface;
this.recalculate();
}
}
public void setExpandedTypeface(Typeface typeface) {
if (this.expandedTypeface != typeface) {
this.expandedTypeface = typeface;
this.recalculate();
}
}
public void setTypefaces(Typeface typeface) {
this.collapsedTypeface = this.expandedTypeface = typeface;
this.recalculate();
}
public Typeface getCollapsedTypeface() {
return this.collapsedTypeface != null ? this.collapsedTypeface : Typeface.DEFAULT;
}
public Typeface getExpandedTypeface() {
return this.expandedTypeface != null ? this.expandedTypeface : Typeface.DEFAULT;
}
public void setExpansionFraction(float fraction) {
fraction = MathUtils.clamp(fraction, 0.0F, 1.0F);
if (fraction != this.expandedFraction) {
this.expandedFraction = fraction;
this.calculateCurrentOffsets();
}
}
public final boolean setState(int[] state) {
this.state = state;
if (this.isStateful()) {
this.recalculate();
return true;
} else {
return false;
}
}
public final boolean isStateful() {
return this.collapsedTextColor != null && this.collapsedTextColor.isStateful() || this.expandedTextColor != null && this.expandedTextColor.isStateful();
}
public float getExpansionFraction() {
return this.expandedFraction;
}
public float getCollapsedTextSize() {
return this.collapsedTextSize;
}
public float getExpandedTextSize() {
return this.expandedTextSize;
}
private void calculateCurrentOffsets() {
this.calculateOffsets(this.expandedFraction);
}
private void calculateOffsets(float fraction) {
this.interpolateBounds(fraction);
this.currentDrawX = lerp(this.expandedDrawX, this.collapsedDrawX, fraction, this.positionInterpolator);
this.currentDrawY = lerp(this.expandedDrawY, this.collapsedDrawY, fraction, this.positionInterpolator);
this.setInterpolatedTextSize(lerp(this.expandedTextSize, this.collapsedTextSize, fraction, this.textSizeInterpolator));
if (this.collapsedTextColor != this.expandedTextColor) {
this.textPaint.setColor(blendColors(this.getCurrentExpandedTextColor(), this.getCurrentCollapsedTextColor(), fraction));
} else {
this.textPaint.setColor(this.getCurrentCollapsedTextColor());
}
this.textPaint.setShadowLayer(lerp(this.expandedShadowRadius, this.collapsedShadowRadius, fraction, (TimeInterpolator)null), lerp(this.expandedShadowDx, this.collapsedShadowDx, fraction, (TimeInterpolator)null), lerp(this.expandedShadowDy, this.collapsedShadowDy, fraction, (TimeInterpolator)null), blendColors(this.expandedShadowColor, this.collapsedShadowColor, fraction));
ViewCompat.postInvalidateOnAnimation(this.view);
}
@ColorInt
private int getCurrentExpandedTextColor() {
return this.state != null ? this.expandedTextColor.getColorForState(this.state, 0) : this.expandedTextColor.getDefaultColor();
}
@ColorInt
@VisibleForTesting
public int getCurrentCollapsedTextColor() {
return this.state != null ? this.collapsedTextColor.getColorForState(this.state, 0) : this.collapsedTextColor.getDefaultColor();
}
private void calculateBaseOffsets() {
float currentTextSize = this.currentTextSize;
this.calculateUsingTextSize(this.collapsedTextSize);
float width = this.textToDraw != null ? this.textPaint.measureText(this.textToDraw, 0, this.textToDraw.length()) : 0.0F;
int collapsedAbsGravity = GravityCompat.getAbsoluteGravity(this.collapsedTextGravity, this.isRtl ? 1 : 0);
float textHeight;
switch(collapsedAbsGravity & 112) {
case 16:
default:
float textHeight = this.textPaint.descent() - this.textPaint.ascent();
textHeight = textHeight / 2.0F - this.textPaint.descent();
this.collapsedDrawY = (float)this.collapsedBounds.centerY() + textHeight;
break;
case 48:
this.collapsedDrawY = (float)this.collapsedBounds.top - this.textPaint.ascent();
break;
case 80:
this.collapsedDrawY = (float)this.collapsedBounds.bottom;
}
switch(collapsedAbsGravity & 8388615) {
case 1:
this.collapsedDrawX = (float)this.collapsedBounds.centerX() - width / 2.0F;
break;
case 2:
case 3:
case 4:
default:
this.collapsedDrawX = (float)this.collapsedBounds.left;
break;
case 5:
this.collapsedDrawX = (float)this.collapsedBounds.right - width;
}
this.calculateUsingTextSize(this.expandedTextSize);
width = this.textToDraw != null ? this.textPaint.measureText(this.textToDraw, 0, this.textToDraw.length()) : 0.0F;
int expandedAbsGravity = GravityCompat.getAbsoluteGravity(this.expandedTextGravity, this.isRtl ? 1 : 0);
switch(expandedAbsGravity & 112) {
case 16:
default:
textHeight = this.textPaint.descent() - this.textPaint.ascent();
float textOffset = textHeight / 2.0F - this.textPaint.descent();
this.expandedDrawY = (float)this.expandedBounds.centerY() + textOffset;
break;
case 48:
this.expandedDrawY = (float)this.expandedBounds.top - this.textPaint.ascent();
break;
case 80:
this.expandedDrawY = (float)this.expandedBounds.bottom;
}
switch(expandedAbsGravity & 8388615) {
case 1:
this.expandedDrawX = (float)this.expandedBounds.centerX() - width / 2.0F;
break;
case 2:
case 3:
case 4:
default:
this.expandedDrawX = (float)this.expandedBounds.left;
break;
case 5:
this.expandedDrawX = (float)this.expandedBounds.right - width;
}
this.clearTexture();
this.setInterpolatedTextSize(currentTextSize);
}
private void interpolateBounds(float fraction) {
this.currentBounds.left = lerp((float)this.expandedBounds.left, (float)this.collapsedBounds.left, fraction, this.positionInterpolator);
this.currentBounds.top = lerp(this.expandedDrawY, this.collapsedDrawY, fraction, this.positionInterpolator);
this.currentBounds.right = lerp((float)this.expandedBounds.right, (float)this.collapsedBounds.right, fraction, this.positionInterpolator);
this.currentBounds.bottom = lerp((float)this.expandedBounds.bottom, (float)this.collapsedBounds.bottom, fraction, this.positionInterpolator);
}
public void draw(Canvas canvas) {
int saveCount = canvas.save();
if (this.textToDraw != null && this.drawTitle) {
float x = this.currentDrawX;
float y = this.currentDrawY;
boolean drawTexture = this.useTexture && this.expandedTitleTexture != null;
float ascent;
if (drawTexture) {
ascent = this.textureAscent * this.scale;
float var10000 = this.textureDescent * this.scale;
} else {
ascent = this.textPaint.ascent() * this.scale;
float var7 = this.textPaint.descent() * this.scale;
}
if (drawTexture) {
y += ascent;
}
if (this.scale != 1.0F) {
canvas.scale(this.scale, this.scale, x, y);
}
if (drawTexture) {
canvas.drawBitmap(this.expandedTitleTexture, x, y, this.texturePaint);
} else {
canvas.drawText(this.textToDraw, 0, this.textToDraw.length(), x, y, this.textPaint);
}
}
canvas.restoreToCount(saveCount);
}
private boolean calculateIsRtl(CharSequence text) {
boolean defaultIsRtl = ViewCompat.getLayoutDirection(this.view) == 1;
return (defaultIsRtl ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL : TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length());
}
private void setInterpolatedTextSize(float textSize) {
this.calculateUsingTextSize(textSize);
this.useTexture = USE_SCALING_TEXTURE && this.scale != 1.0F;
if (this.useTexture) {
this.ensureExpandedTexture();
}
ViewCompat.postInvalidateOnAnimation(this.view);
}
private void calculateUsingTextSize(float textSize) {
if (this.text != null) {
float collapsedWidth = (float)this.collapsedBounds.width();
float expandedWidth = (float)this.expandedBounds.width();
boolean updateDrawText = false;
float availableWidth;
float newTextSize;
if (isClose(textSize, this.collapsedTextSize)) {
newTextSize = this.collapsedTextSize;
this.scale = 1.0F;
if (this.currentTypeface != this.collapsedTypeface) {
this.currentTypeface = this.collapsedTypeface;
updateDrawText = true;
}
availableWidth = collapsedWidth;
} else {
newTextSize = this.expandedTextSize;
if (this.currentTypeface != this.expandedTypeface) {
this.currentTypeface = this.expandedTypeface;
updateDrawText = true;
}
if (isClose(textSize, this.expandedTextSize)) {
this.scale = 1.0F;
} else {
this.scale = textSize / this.expandedTextSize;
}
float textSizeRatio = this.collapsedTextSize / this.expandedTextSize;
float scaledDownWidth = expandedWidth * textSizeRatio;
if (scaledDownWidth > collapsedWidth) {
availableWidth = Math.min(collapsedWidth / textSizeRatio, expandedWidth);
} else {
availableWidth = expandedWidth;
}
}
if (availableWidth > 0.0F) {
updateDrawText = this.currentTextSize != newTextSize || this.boundsChanged || updateDrawText;
this.currentTextSize = newTextSize;
this.boundsChanged = false;
}
if (this.textToDraw == null || updateDrawText) {
this.textPaint.setTextSize(this.currentTextSize);
this.textPaint.setTypeface(this.currentTypeface);
this.textPaint.setLinearText(this.scale != 1.0F);
CharSequence title = TextUtils.ellipsize(this.text, this.textPaint, availableWidth, TruncateAt.END);
if (!TextUtils.equals(title, this.textToDraw)) {
this.textToDraw = title;
this.isRtl = this.calculateIsRtl(this.textToDraw);
}
}
}
}
private void ensureExpandedTexture() {
if (this.expandedTitleTexture == null && !this.expandedBounds.isEmpty() && !TextUtils.isEmpty(this.textToDraw)) {
this.calculateOffsets(0.0F);
this.textureAscent = this.textPaint.ascent();
this.textureDescent = this.textPaint.descent();
int w = Math.round(this.textPaint.measureText(this.textToDraw, 0, this.textToDraw.length()));
int h = Math.round(this.textureDescent - this.textureAscent);
if (w > 0 && h > 0) {
this.expandedTitleTexture = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas c = new Canvas(this.expandedTitleTexture);
c.drawText(this.textToDraw, 0, this.textToDraw.length(), 0.0F, (float)h - this.textPaint.descent(), this.textPaint);
if (this.texturePaint == null) {
this.texturePaint = new Paint(3);
}
}
}
}
public void recalculate() {
if (this.view.getHeight() > 0 && this.view.getWidth() > 0) {
this.calculateBaseOffsets();
this.calculateCurrentOffsets();
}
}
public void setText(CharSequence text) {
if (text == null || !text.equals(this.text)) {
this.text = text;
this.textToDraw = null;
this.clearTexture();
this.recalculate();
}
}
public CharSequence getText() {
return this.text;
}
private void clearTexture() {
if (this.expandedTitleTexture != null) {
this.expandedTitleTexture.recycle();
this.expandedTitleTexture = null;
}
}
private static boolean isClose(float value, float targetValue) {
return Math.abs(value - targetValue) < 0.001F;
}
public ColorStateList getExpandedTextColor() {
return this.expandedTextColor;
}
public ColorStateList getCollapsedTextColor() {
return this.collapsedTextColor;
}
private static int blendColors(int color1, int color2, float ratio) {
float inverseRatio = 1.0F - ratio;
float a = (float)Color.alpha(color1) * inverseRatio + (float)Color.alpha(color2) * ratio;
float r = (float)Color.red(color1) * inverseRatio + (float)Color.red(color2) * ratio;
float g = (float)Color.green(color1) * inverseRatio + (float)Color.green(color2) * ratio;
float b = (float)Color.blue(color1) * inverseRatio + (float)Color.blue(color2) * ratio;
return Color.argb((int)a, (int)r, (int)g, (int)b);
}
private static float lerp(float startValue, float endValue, float fraction, TimeInterpolator interpolator) {
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
return AnimationUtils.lerp(startValue, endValue, fraction);
}
private static boolean rectEquals(Rect r, int left, int top, int right, int bottom) {
return r.left == left && r.top == top && r.right == right && r.bottom == bottom;
}
static {
USE_SCALING_TEXTURE = VERSION.SDK_INT < 18;
DEBUG_DRAW_PAINT = null;
if (DEBUG_DRAW_PAINT != null) {
DEBUG_DRAW_PAINT.setAntiAlias(true);
DEBUG_DRAW_PAINT.setColor(-65281);
}
}
}
`
CollapsingToolbarLayout
`
package android.support.design.widget;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.Callback;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.StyleRes;
import android.support.design.R.id;
import android.support.design.R.style;
import android.support.design.R.styleable;
import android.support.design.animation.AnimationUtils;
import android.support.design.internal.ThemeEnforcement;
import android.support.design.widget.AppBarLayout.OnOffsetChangedListener;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.math.MathUtils;
import android.support.v4.util.ObjectsCompat;
import android.support.v4.view.OnApplyWindowInsetsListener;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.WindowInsetsCompat;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.View.MeasureSpec;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.FrameLayout;
public class CollapsingToolbarLayout extends FrameLayout {
private static final int DEFAULT_SCRIM_ANIMATION_DURATION = 600;
private boolean refreshToolbar;
private int toolbarId;
private Toolbar toolbar;
private View toolbarDirectChild;
private View dummyView;
private int expandedMarginStart;
private int expandedMarginTop;
private int expandedMarginEnd;
private int expandedMarginBottom;
private final Rect tmpRect;
final CollapsingTextHelper collapsingTextHelper;
private boolean collapsingTitleEnabled;
private boolean drawCollapsingTitle;
private Drawable contentScrim;
Drawable statusBarScrim;
private int scrimAlpha;
private boolean scrimsAreShown;
private ValueAnimator scrimAnimator;
private long scrimAnimationDuration;
private int scrimVisibleHeightTrigger;
private OnOffsetChangedListener onOffsetChangedListener;
int currentOffset;
WindowInsetsCompat lastInsets;
public CollapsingToolbarLayout(Context context) {
this(context, (AttributeSet)null);
}
public CollapsingToolbarLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.refreshToolbar = true;
this.tmpRect = new Rect();
this.scrimVisibleHeightTrigger = -1;
this.collapsingTextHelper = new CollapsingTextHelper(this);
this.collapsingTextHelper.setTextSizeInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
TypedArray a = ThemeEnforcement.obtainStyledAttributes(context, attrs, styleable.CollapsingToolbarLayout, defStyleAttr, style.Widget_Design_CollapsingToolbar, new int[0]);
this.collapsingTextHelper.setExpandedTextGravity(a.getInt(styleable.CollapsingToolbarLayout_expandedTitleGravity, 8388691));
this.collapsingTextHelper.setCollapsedTextGravity(a.getInt(styleable.CollapsingToolbarLayout_collapsedTitleGravity, 8388627));
this.expandedMarginStart = this.expandedMarginTop = this.expandedMarginEnd = this.expandedMarginBottom = a.getDimensionPixelSize(styleable.CollapsingToolbarLayout_expandedTitleMargin, 0);
if (a.hasValue(styleable.CollapsingToolbarLayout_expandedTitleMarginStart)) {
this.expandedMarginStart = a.getDimensionPixelSize(styleable.CollapsingToolbarLayout_expandedTitleMarginStart, 0);
}
if (a.hasValue(styleable.CollapsingToolbarLayout_expandedTitleMarginEnd)) {
this.expandedMarginEnd = a.getDimensionPixelSize(styleable.CollapsingToolbarLayout_expandedTitleMarginEnd, 0);
}
if (a.hasValue(styleable.CollapsingToolbarLayout_expandedTitleMarginTop)) {
this.expandedMarginTop = a.getDimensionPixelSize(styleable.CollapsingToolbarLayout_expandedTitleMarginTop, 0);
}
if (a.hasValue(styleable.CollapsingToolbarLayout_expandedTitleMarginBottom)) {
this.expandedMarginBottom = a.getDimensionPixelSize(styleable.CollapsingToolbarLayout_expandedTitleMarginBottom, 0);
}
this.collapsingTitleEnabled = a.getBoolean(styleable.CollapsingToolbarLayout_titleEnabled, true);
this.setTitle(a.getText(styleable.CollapsingToolbarLayout_title));
this.collapsingTextHelper.setExpandedTextAppearance(style.TextAppearance_Design_CollapsingToolbar_Expanded);
this.collapsingTextHelper.setCollapsedTextAppearance(android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Widget_ActionBar_Title);
if (a.hasValue(styleable.CollapsingToolbarLayout_expandedTitleTextAppearance)) {
this.collapsingTextHelper.setExpandedTextAppearance(a.getResourceId(styleable.CollapsingToolbarLayout_expandedTitleTextAppearance, 0));
}
if (a.hasValue(styleable.CollapsingToolbarLayout_collapsedTitleTextAppearance)) {
this.collapsingTextHelper.setCollapsedTextAppearance(a.getResourceId(styleable.CollapsingToolbarLayout_collapsedTitleTextAppearance, 0));
}
this.scrimVisibleHeightTrigger = a.getDimensionPixelSize(styleable.CollapsingToolbarLayout_scrimVisibleHeightTrigger, -1);
this.scrimAnimationDuration = (long)a.getInt(styleable.CollapsingToolbarLayout_scrimAnimationDuration, 600);
this.setContentScrim(a.getDrawable(styleable.CollapsingToolbarLayout_contentScrim));
this.setStatusBarScrim(a.getDrawable(styleable.CollapsingToolbarLayout_statusBarScrim));
this.toolbarId = a.getResourceId(styleable.CollapsingToolbarLayout_toolbarId, -1);
a.recycle();
this.setWillNotDraw(false);
ViewCompat.setOnApplyWindowInsetsListener(this, new OnApplyWindowInsetsListener() {
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
return CollapsingToolbarLayout.this.onWindowInsetChanged(insets);
}
});
}
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ViewParent parent = this.getParent();
if (parent instanceof AppBarLayout) {
ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View)parent));
if (this.onOffsetChangedListener == null) {
this.onOffsetChangedListener = new CollapsingToolbarLayout.OffsetUpdateListener();
}
((AppBarLayout)parent).addOnOffsetChangedListener(this.onOffsetChangedListener);
ViewCompat.requestApplyInsets(this);
}
}
protected void onDetachedFromWindow() {
ViewParent parent = this.getParent();
if (this.onOffsetChangedListener != null && parent instanceof AppBarLayout) {
((AppBarLayout)parent).removeOnOffsetChangedListener(this.onOffsetChangedListener);
}
super.onDetachedFromWindow();
}
WindowInsetsCompat onWindowInsetChanged(WindowInsetsCompat insets) {
WindowInsetsCompat newInsets = null;
if (ViewCompat.getFitsSystemWindows(this)) {
newInsets = insets;
}
if (!ObjectsCompat.equals(this.lastInsets, newInsets)) {
this.lastInsets = newInsets;
this.requestLayout();
}
return insets.consumeSystemWindowInsets();
}
public void draw(Canvas canvas) {
super.draw(canvas);
this.ensureToolbar();
if (this.toolbar == null && this.contentScrim != null && this.scrimAlpha > 0) {
this.contentScrim.mutate().setAlpha(this.scrimAlpha);
this.contentScrim.draw(canvas);
}
if (this.collapsingTitleEnabled && this.drawCollapsingTitle) {
this.collapsingTextHelper.draw(canvas);
}
if (this.statusBarScrim != null && this.scrimAlpha > 0) {
int topInset = this.lastInsets != null ? this.lastInsets.getSystemWindowInsetTop() : 0;
if (topInset > 0) {
this.statusBarScrim.setBounds(0, -this.currentOffset, this.getWidth(), topInset - this.currentOffset);
this.statusBarScrim.mutate().setAlpha(this.scrimAlpha);
this.statusBarScrim.draw(canvas);
}
}
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean invalidated = false;
if (this.contentScrim != null && this.scrimAlpha > 0 && this.isToolbarChild(child)) {
this.contentScrim.mutate().setAlpha(this.scrimAlpha);
this.contentScrim.draw(canvas);
invalidated = true;
}
return super.drawChild(canvas, child, drawingTime) || invalidated;
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (this.contentScrim != null) {
this.contentScrim.setBounds(0, 0, w, h);
}
}
private void ensureToolbar() {
if (this.refreshToolbar) {
this.toolbar = null;
this.toolbarDirectChild = null;
if (this.toolbarId != -1) {
this.toolbar = (Toolbar)this.findViewById(this.toolbarId);
if (this.toolbar != null) {
this.toolbarDirectChild = this.findDirectChild(this.toolbar);
}
}
if (this.toolbar == null) {
Toolbar toolbar = null;
int i = 0;
for(int count = this.getChildCount(); i < count; ++i) {
View child = this.getChildAt(i);
if (child instanceof Toolbar) {
toolbar = (Toolbar)child;
break;
}
}
this.toolbar = toolbar;
}
this.updateDummyView();
this.refreshToolbar = false;
}
}
private boolean isToolbarChild(View child) {
return this.toolbarDirectChild != null && this.toolbarDirectChild != this ? child == this.toolbarDirectChild : child == this.toolbar;
}
private View findDirectChild(View descendant) {
View directChild = descendant;
for(ViewParent p = descendant.getParent(); p != this && p != null; p = p.getParent()) {
if (p instanceof View) {
directChild = (View)p;
}
}
return directChild;
}
private void updateDummyView() {
if (!this.collapsingTitleEnabled && this.dummyView != null) {
ViewParent parent = this.dummyView.getParent();
if (parent instanceof ViewGroup) {
((ViewGroup)parent).removeView(this.dummyView);
}
}
if (this.collapsingTitleEnabled && this.toolbar != null) {
if (this.dummyView == null) {
this.dummyView = new View(this.getContext());
}
if (this.dummyView.getParent() == null) {
this.toolbar.addView(this.dummyView, -1, -1);
}
}
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.ensureToolbar();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mode = MeasureSpec.getMode(heightMeasureSpec);
int topInset = this.lastInsets != null ? this.lastInsets.getSystemWindowInsetTop() : 0;
if (mode == 0 && topInset > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(this.getMeasuredHeight() + topInset, 1073741824);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int i;
int z;
if (this.lastInsets != null) {
i = this.lastInsets.getSystemWindowInsetTop();
z = 0;
for(int z = this.getChildCount(); z < z; ++z) {
View child = this.getChildAt(z);
if (!ViewCompat.getFitsSystemWindows(child) && child.getTop() < i) {
ViewCompat.offsetTopAndBottom(child, i);
}
}
}
if (this.collapsingTitleEnabled && this.dummyView != null) {
this.drawCollapsingTitle = ViewCompat.isAttachedToWindow(this.dummyView) && this.dummyView.getVisibility() == 0;
if (this.drawCollapsingTitle) {
boolean isRtl = ViewCompat.getLayoutDirection(this) == 1;
z = this.getMaxOffsetForPinChild((View)(this.toolbarDirectChild != null ? this.toolbarDirectChild : this.toolbar));
DescendantOffsetUtils.getDescendantRect(this, this.dummyView, this.tmpRect);
this.collapsingTextHelper.setCollapsedBounds(this.tmpRect.left + (isRtl ? this.toolbar.getTitleMarginEnd() : this.toolbar.getTitleMarginStart()), this.tmpRect.top + z + this.toolbar.getTitleMarginTop(), this.tmpRect.right + (isRtl ? this.toolbar.getTitleMarginStart() : this.toolbar.getTitleMarginEnd()), this.tmpRect.bottom + z - this.toolbar.getTitleMarginBottom());
this.collapsingTextHelper.setExpandedBounds(isRtl ? this.expandedMarginEnd : this.expandedMarginStart, this.tmpRect.top + this.expandedMarginTop, right - left - (isRtl ? this.expandedMarginStart : this.expandedMarginEnd), bottom - top - this.expandedMarginBottom);
this.collapsingTextHelper.recalculate();
}
}
i = 0;
for(z = this.getChildCount(); i < z; ++i) {
getViewOffsetHelper(this.getChildAt(i)).onViewLayout();
}
if (this.toolbar != null) {
if (this.collapsingTitleEnabled && TextUtils.isEmpty(this.collapsingTextHelper.getText())) {
this.setTitle(this.toolbar.getTitle());
}
if (this.toolbarDirectChild != null && this.toolbarDirectChild != this) {
this.setMinimumHeight(getHeightWithMargins(this.toolbarDirectChild));
} else {
this.setMinimumHeight(getHeightWithMargins(this.toolbar));
}
}
this.updateScrimVisibility();
}
private static int getHeightWithMargins(@NonNull View view) {
android.view.ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp instanceof MarginLayoutParams) {
MarginLayoutParams mlp = (MarginLayoutParams)lp;
return view.getHeight() + mlp.topMargin + mlp.bottomMargin;
} else {
return view.getHeight();
}
}
static ViewOffsetHelper getViewOffsetHelper(View view) {
ViewOffsetHelper offsetHelper = (ViewOffsetHelper)view.getTag(id.view_offset_helper);
if (offsetHelper == null) {
offsetHelper = new ViewOffsetHelper(view);
view.setTag(id.view_offset_helper, offsetHelper);
}
return offsetHelper;
}
public void setTitle(@Nullable CharSequence title) {
this.collapsingTextHelper.setText(title);
this.updateContentDescriptionFromTitle();
}
@Nullable
public CharSequence getTitle() {
return this.collapsingTitleEnabled ? this.collapsingTextHelper.getText() : null;
}
public void setTitleEnabled(boolean enabled) {
if (enabled != this.collapsingTitleEnabled) {
this.collapsingTitleEnabled = enabled;
this.updateContentDescriptionFromTitle();
this.updateDummyView();
this.requestLayout();
}
}
public boolean isTitleEnabled() {
return this.collapsingTitleEnabled;
}
public void setScrimsShown(boolean shown) {
this.setScrimsShown(shown, ViewCompat.isLaidOut(this) && !this.isInEditMode());
}
public void setScrimsShown(boolean shown, boolean animate) {
if (this.scrimsAreShown != shown) {
if (animate) {
this.animateScrim(shown ? 255 : 0);
} else {
this.setScrimAlpha(shown ? 255 : 0);
}
this.scrimsAreShown = shown;
}
}
private void animateScrim(int targetAlpha) {
this.ensureToolbar();
if (this.scrimAnimator == null) {
this.scrimAnimator = new ValueAnimator();
this.scrimAnimator.setDuration(this.scrimAnimationDuration);
this.scrimAnimator.setInterpolator(targetAlpha > this.scrimAlpha ? AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR : AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
this.scrimAnimator.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animator) {
CollapsingToolbarLayout.this.setScrimAlpha((Integer)animator.getAnimatedValue());
}
});
} else if (this.scrimAnimator.isRunning()) {
this.scrimAnimator.cancel();
}
this.scrimAnimator.setIntValues(new int[]{this.scrimAlpha, targetAlpha});
this.scrimAnimator.start();
}
void setScrimAlpha(int alpha) {
if (alpha != this.scrimAlpha) {
Drawable contentScrim = this.contentScrim;
if (contentScrim != null && this.toolbar != null) {
ViewCompat.postInvalidateOnAnimation(this.toolbar);
}
this.scrimAlpha = alpha;
ViewCompat.postInvalidateOnAnimation(this);
}
}
int getScrimAlpha() {
return this.scrimAlpha;
}
public void setContentScrim(@Nullable Drawable drawable) {
if (this.contentScrim != drawable) {
if (this.contentScrim != null) {
this.contentScrim.setCallback((Callback)null);
}
this.contentScrim = drawable != null ? drawable.mutate() : null;
if (this.contentScrim != null) {
this.contentScrim.setBounds(0, 0, this.getWidth(), this.getHeight());
this.contentScrim.setCallback(this);
this.contentScrim.setAlpha(this.scrimAlpha);
}
ViewCompat.postInvalidateOnAnimation(this);
}
}
public void setContentScrimColor(@ColorInt int color) {
this.setContentScrim(new ColorDrawable(color));
}
public void setContentScrimResource(@DrawableRes int resId) {
this.setContentScrim(ContextCompat.getDrawable(this.getContext(), resId));
}
@Nullable
public Drawable getContentScrim() {
return this.contentScrim;
}
public void setStatusBarScrim(@Nullable Drawable drawable) {
if (this.statusBarScrim != drawable) {
if (this.statusBarScrim != null) {
this.statusBarScrim.setCallback((Callback)null);
}
this.statusBarScrim = drawable != null ? drawable.mutate() : null;
if (this.statusBarScrim != null) {
if (this.statusBarScrim.isStateful()) {
this.statusBarScrim.setState(this.getDrawableState());
}
DrawableCompat.setLayoutDirection(this.statusBarScrim, ViewCompat.getLayoutDirection(this));
this.statusBarScrim.setVisible(this.getVisibility() == 0, false);
this.statusBarScrim.setCallback(this);
this.statusBarScrim.setAlpha(this.scrimAlpha);
}
ViewCompat.postInvalidateOnAnimation(this);
}
}
protected void drawableStateChanged() {
super.drawableStateChanged();
int[] state = this.getDrawableState();
boolean changed = false;
Drawable d = this.statusBarScrim;
if (d != null && d.isStateful()) {
changed |= d.setState(state);
}
d = this.contentScrim;
if (d != null && d.isStateful()) {
changed |= d.setState(state);
}
if (this.collapsingTextHelper != null) {
changed |= this.collapsingTextHelper.setState(state);
}
if (changed) {
this.invalidate();
}
}
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == this.contentScrim || who == this.statusBarScrim;
}
public void setVisibility(int visibility) {
super.setVisibility(visibility);
boolean visible = visibility == 0;
if (this.statusBarScrim != null && this.statusBarScrim.isVisible() != visible) {
this.statusBarScrim.setVisible(visible, false);
}
if (this.contentScrim != null && this.contentScrim.isVisible() != visible) {
this.contentScrim.setVisible(visible, false);
}
}
public void setStatusBarScrimColor(@ColorInt int color) {
this.setStatusBarScrim(new ColorDrawable(color));
}
public void setStatusBarScrimResource(@DrawableRes int resId) {
this.setStatusBarScrim(ContextCompat.getDrawable(this.getContext(), resId));
}
@Nullable
public Drawable getStatusBarScrim() {
return this.statusBarScrim;
}
public void setCollapsedTitleTextAppearance(@StyleRes int resId) {
this.collapsingTextHelper.setCollapsedTextAppearance(resId);
}
public void setCollapsedTitleTextColor(@ColorInt int color) {
this.setCollapsedTitleTextColor(ColorStateList.valueOf(color));
}
public void setCollapsedTitleTextColor(@NonNull ColorStateList colors) {
this.collapsingTextHelper.setCollapsedTextColor(colors);
}
public void setCollapsedTitleGravity(int gravity) {
this.collapsingTextHelper.setCollapsedTextGravity(gravity);
}
public int getCollapsedTitleGravity() {
return this.collapsingTextHelper.getCollapsedTextGravity();
}
public void setExpandedTitleTextAppearance(@StyleRes int resId) {
this.collapsingTextHelper.setExpandedTextAppearance(resId);
}
public void setExpandedTitleColor(@ColorInt int color) {
this.setExpandedTitleTextColor(ColorStateList.valueOf(color));
}
public void setExpandedTitleTextColor(@NonNull ColorStateList colors) {
this.collapsingTextHelper.setExpandedTextColor(colors);
}
public void setExpandedTitleGravity(int gravity) {
this.collapsingTextHelper.setExpandedTextGravity(gravity);
}
public int getExpandedTitleGravity() {
return this.collapsingTextHelper.getExpandedTextGravity();
}
public void setCollapsedTitleTypeface(@Nullable Typeface typeface) {
this.collapsingTextHelper.setCollapsedTypeface(typeface);
}
@NonNull
public Typeface getCollapsedTitleTypeface() {
return this.collapsingTextHelper.getCollapsedTypeface();
}
public void setExpandedTitleTypeface(@Nullable Typeface typeface) {
this.collapsingTextHelper.setExpandedTypeface(typeface);
}
@NonNull
public Typeface getExpandedTitleTypeface() {
return this.collapsingTextHelper.getExpandedTypeface();
}
public void setExpandedTitleMargin(int start, int top, int end, int bottom) {
this.expandedMarginStart = start;
this.expandedMarginTop = top;
this.expandedMarginEnd = end;
this.expandedMarginBottom = bottom;
this.requestLayout();
}
public int getExpandedTitleMarginStart() {
return this.expandedMarginStart;
}
public void setExpandedTitleMarginStart(int margin) {
this.expandedMarginStart = margin;
this.requestLayout();
}
public int getExpandedTitleMarginTop() {
return this.expandedMarginTop;
}
public void setExpandedTitleMarginTop(int margin) {
this.expandedMarginTop = margin;
this.requestLayout();
}
public int getExpandedTitleMarginEnd() {
return this.expandedMarginEnd;
}
public void setExpandedTitleMarginEnd(int margin) {
this.expandedMarginEnd = margin;
this.requestLayout();
}
public int getExpandedTitleMarginBottom() {
return this.expandedMarginBottom;
}
public void setExpandedTitleMarginBottom(int margin) {
this.expandedMarginBottom = margin;
this.requestLayout();
}
public void setScrimVisibleHeightTrigger(@IntRange(from = 0L) int height) {
if (this.scrimVisibleHeightTrigger != height) {
this.scrimVisibleHeightTrigger = height;
this.updateScrimVisibility();
}
}
public int getScrimVisibleHeightTrigger() {
if (this.scrimVisibleHeightTrigger >= 0) {
return this.scrimVisibleHeightTrigger;
} else {
int insetTop = this.lastInsets != null ? this.lastInsets.getSystemWindowInsetTop() : 0;
int minHeight = ViewCompat.getMinimumHeight(this);
return minHeight > 0 ? Math.min(minHeight * 2 + insetTop, this.getHeight()) : this.getHeight() / 3;
}
}
public void setScrimAnimationDuration(@IntRange(from = 0L) long duration) {
this.scrimAnimationDuration = duration;
}
public long getScrimAnimationDuration() {
return this.scrimAnimationDuration;
}
protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
return p instanceof CollapsingToolbarLayout.LayoutParams;
}
protected CollapsingToolbarLayout.LayoutParams generateDefaultLayoutParams() {
return new CollapsingToolbarLayout.LayoutParams(-1, -1);
}
public android.widget.FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new CollapsingToolbarLayout.LayoutParams(this.getContext(), attrs);
}
protected android.widget.FrameLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams p) {
return new CollapsingToolbarLayout.LayoutParams(p);
}
final void updateScrimVisibility() {
if (this.contentScrim != null || this.statusBarScrim != null) {
this.setScrimsShown(this.getHeight() + this.currentOffset < this.getScrimVisibleHeightTrigger());
}
}
final int getMaxOffsetForPinChild(View child) {
ViewOffsetHelper offsetHelper = getViewOffsetHelper(child);
CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams)child.getLayoutParams();
return this.getHeight() - offsetHelper.getLayoutTop() - child.getHeight() - lp.bottomMargin;
}
private void updateContentDescriptionFromTitle() {
this.setContentDescription(this.getTitle());
}
private class OffsetUpdateListener implements OnOffsetChangedListener {
OffsetUpdateListener() {
}
public void onOffsetChanged(AppBarLayout layout, int verticalOffset) {
CollapsingToolbarLayout.this.currentOffset = verticalOffset;
int insetTop = CollapsingToolbarLayout.this.lastInsets != null ? CollapsingToolbarLayout.this.lastInsets.getSystemWindowInsetTop() : 0;
int expandRange = 0;
for(int z = CollapsingToolbarLayout.this.getChildCount(); expandRange < z; ++expandRange) {
View child = CollapsingToolbarLayout.this.getChildAt(expandRange);
CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams)child.getLayoutParams();
ViewOffsetHelper offsetHelper = CollapsingToolbarLayout.getViewOffsetHelper(child);
switch(lp.collapseMode) {
case 1:
offsetHelper.setTopAndBottomOffset(MathUtils.clamp(-verticalOffset, 0, CollapsingToolbarLayout.this.getMaxOffsetForPinChild(child)));
break;
case 2:
offsetHelper.setTopAndBottomOffset(Math.round((float)(-verticalOffset) * lp.parallaxMult));
}
}
CollapsingToolbarLayout.this.updateScrimVisibility();
if (CollapsingToolbarLayout.this.statusBarScrim != null && insetTop > 0) {
ViewCompat.postInvalidateOnAnimation(CollapsingToolbarLayout.this);
}
expandRange = CollapsingToolbarLayout.this.getHeight() - ViewCompat.getMinimumHeight(CollapsingToolbarLayout.this) - insetTop;
CollapsingToolbarLayout.this.collapsingTextHelper.setExpansionFraction((float)Math.abs(verticalOffset) / (float)expandRange);
}
}
public static class LayoutParams extends android.widget.FrameLayout.LayoutParams {
private static final float DEFAULT_PARALLAX_MULTIPLIER = 0.5F;
public static final int COLLAPSE_MODE_OFF = 0;
public static final int COLLAPSE_MODE_PIN = 1;
public static final int COLLAPSE_MODE_PARALLAX = 2;
int collapseMode = 0;
float parallaxMult = 0.5F;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs, styleable.CollapsingToolbarLayout_Layout);
this.collapseMode = a.getInt(styleable.CollapsingToolbarLayout_Layout_layout_collapseMode, 0);
this.setParallaxMultiplier(a.getFloat(styleable.CollapsingToolbarLayout_Layout_layout_collapseParallaxMultiplier, 0.5F));
a.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(int width, int height, int gravity) {
super(width, height, gravity);
}
public LayoutParams(android.view.ViewGroup.LayoutParams p) {
super(p);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
@RequiresApi(19)
public LayoutParams(android.widget.FrameLayout.LayoutParams source) {
super(source);
}
public void setCollapseMode(int collapseMode) {
this.collapseMode = collapseMode;
}
public int getCollapseMode() {
return this.collapseMode;
}
public void setParallaxMultiplier(float multiplier) {
this.parallaxMult = multiplier;
}
public float getParallaxMultiplier() {
return this.parallaxMult;
}
}
}
`
Hope this somehow helps!! :)
from collapsingtoolbarlayout-subtitle.
Hi @gupta-shubham-im, may I know where did you get these? I'm just making sure they are indeed from support library 28.0.0.
from collapsingtoolbarlayout-subtitle.
Actually these are decompiled classes from Android Studio, I have an existing project which has design support library version 28.0.0, so got it from there
from collapsingtoolbarlayout-subtitle.
Sorry I didn't review the code when I replied. I can't use decompiled classes because I couldn't see some of the generated resources ids, as they appear as integers.
from collapsingtoolbarlayout-subtitle.
Hi let me know what all resources are not available, I'll try and find out their actual values
from collapsingtoolbarlayout-subtitle.
There's just so many of them I don't know where to start. I will wait until the sources of support library 28 is available.
In the meantime, if you really can't wait, you can just have a copy of branch support
in your project. They are working, just not much tested.
from collapsingtoolbarlayout-subtitle.
Any updates?
from collapsingtoolbarlayout-subtitle.
I don't know where I went wrong, sources of support 28 still isn't available to me.
from collapsingtoolbarlayout-subtitle.
Hi @hendraanggrian , why don't you take the source code of your current library and just replace the androidx package imports with the Android support package imports, it should work for 28.0.0 version
from collapsingtoolbarlayout-subtitle.
Anyone tried @gupta-shubham-im 's solution? I'm stuck with between this library not supporting 28 and other 3rd party libraries not supporting AndroidX. v28 support for this library seems to be the most viable path to getting my app working again...
from collapsingtoolbarlayout-subtitle.
I can confirm the support
branch has a working copy of this library in legacy 28.0.0. I have not uploaded it only because I haven't seen the code myself, and it's hard to fully test without them.
from collapsingtoolbarlayout-subtitle.
Closed for inactivity.
from collapsingtoolbarlayout-subtitle.
Related Issues (20)
- Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.design.widget.ViewGroupUtils" on path: DexPathList HOT 9
- Add support for 27.1.0? HOT 3
- Support for androidx 1.0.0 HOT 12
- Issues with Navigation Drawer HOT 10
- Propose app logo HOT 7
- expandedSubtitleTextAppearance bug with shadows HOT 5
- Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.design.widget.ThemeUtils" on path: DexPathList HOT 3
- Set subtitle programmatically HOT 1
- Legacy artifact not resolved HOT 1
- Is there any way to show subtitle only in collapsed mode and not in expanded mode? HOT 2
- Title and subtitle display issue. HOT 3
- No collapsedTitleMargin HOT 1
- Sometimes subtitle is not showed in collapsed state in toolbar HOT 2
- New release planned for version 1.1.0 of material ? HOT 2
- support navigation component HOT 1
- Need subtitle click listener HOT 1
- Navigation icon in toolbar -> title gravity issue HOT 1
- Migrate to mavenCentral HOT 2
- Error inflating class com.google.android.material.appbar.SubtitleCollapsingToolbarLayout HOT 17
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from collapsingtoolbarlayout-subtitle.