Code Monkey home page Code Monkey logo

Comments (22)

CHRehan avatar CHRehan commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

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.

CHRehan avatar CHRehan commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

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.

gupta-shubham-im avatar gupta-shubham-im commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

I am considering adding support to support library 28. Will update when I have more information.

from collapsingtoolbarlayout-subtitle.

akshattailang94 avatar akshattailang94 commented on September 28, 2024

Any update on release to support library 28?

from collapsingtoolbarlayout-subtitle.

JulianBissekkou avatar JulianBissekkou commented on September 28, 2024

Any updates?

from collapsingtoolbarlayout-subtitle.

bhaskardonadapti5 avatar bhaskardonadapti5 commented on September 28, 2024

Any update on this ?

from collapsingtoolbarlayout-subtitle.

hanggrian avatar hanggrian commented on September 28, 2024

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.

gupta-shubham-im avatar gupta-shubham-im commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

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.

gupta-shubham-im avatar gupta-shubham-im commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

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.

gupta-shubham-im avatar gupta-shubham-im commented on September 28, 2024

Hi let me know what all resources are not available, I'll try and find out their actual values

from collapsingtoolbarlayout-subtitle.

hanggrian avatar hanggrian commented on September 28, 2024

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.

Alexinfos avatar Alexinfos commented on September 28, 2024

Any updates?

from collapsingtoolbarlayout-subtitle.

hanggrian avatar hanggrian commented on September 28, 2024

Screen Shot 2019-06-07 at 1 59 32 AM

I don't know where I went wrong, sources of support 28 still isn't available to me.

from collapsingtoolbarlayout-subtitle.

gupta-shubham-im avatar gupta-shubham-im commented on September 28, 2024

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.

jeremy303 avatar jeremy303 commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

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.

hanggrian avatar hanggrian commented on September 28, 2024

Closed for inactivity.

from collapsingtoolbarlayout-subtitle.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.