1c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes/* 2c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Copyright (C) 2015 The Android Open Source Project 3c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 4c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * you may not use this file except in compliance with the License. 6c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * You may obtain a copy of the License at 7c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 8c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 9c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 10c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Unless required by applicable law or agreed to in writing, software 11c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * See the License for the specific language governing permissions and 14c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * limitations under the License. 15c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */ 16c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 17c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banespackage android.support.design.widget; 18c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 19c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.content.res.TypedArray; 20c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Bitmap; 21c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Canvas; 22c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Color; 23c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Paint; 24c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Rect; 255c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banesimport android.graphics.RectF; 26388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banesimport android.graphics.Typeface; 27c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.os.Build; 28c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.design.R; 29fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banesimport android.support.v4.text.TextDirectionHeuristicsCompat; 305c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banesimport android.support.v4.view.GravityCompat; 31c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.v4.view.ViewCompat; 32c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.text.TextPaint; 33c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.text.TextUtils; 34c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.Gravity; 35c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.View; 36c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.animation.Interpolator; 37c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 38c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesfinal class CollapsingTextHelper { 39c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 40c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // Pre-JB-MR2 doesn't support HW accelerated canvas scaled text so we will workaround it 41c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // by using our own texture 42c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private static final boolean USE_SCALING_TEXTURE = Build.VERSION.SDK_INT < 18; 43c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 44c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private static final boolean DEBUG_DRAW = false; 45c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private static final Paint DEBUG_DRAW_PAINT; 46c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes static { 47c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes DEBUG_DRAW_PAINT = DEBUG_DRAW ? new Paint() : null; 48c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (DEBUG_DRAW_PAINT != null) { 49c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes DEBUG_DRAW_PAINT.setAntiAlias(true); 50c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes DEBUG_DRAW_PAINT.setColor(Color.MAGENTA); 51c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 52c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 53c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 54c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private final View mView; 55c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 5666a875e525700de5eed715a52a3329ab5a310d96Chris Banes private boolean mDrawTitle; 57c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private float mExpandedFraction; 58c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 59c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private final Rect mExpandedBounds; 60c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private final Rect mCollapsedBounds; 615c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private final RectF mCurrentBounds; 625c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private int mExpandedTextGravity = Gravity.CENTER_VERTICAL; 635c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private int mCollapsedTextGravity = Gravity.CENTER_VERTICAL; 649934230aa2959ee9f1802aa81fd21e25030b0d10Chris Banes private float mExpandedTextSize = 15; 659934230aa2959ee9f1802aa81fd21e25030b0d10Chris Banes private float mCollapsedTextSize = 15; 66c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private int mExpandedTextColor; 67c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private int mCollapsedTextColor; 68c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 695c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private float mExpandedDrawY; 705c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private float mCollapsedDrawY; 715c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private float mExpandedDrawX; 725c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private float mCollapsedDrawX; 735c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private float mCurrentDrawX; 745c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private float mCurrentDrawY; 75d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes private Typeface mCollapsedTypeface; 76d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes private Typeface mExpandedTypeface; 77d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes private Typeface mCurrentTypeface; 78c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 79c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private CharSequence mText; 80c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private CharSequence mTextToDraw; 81fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes private boolean mIsRtl; 82c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 83c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private boolean mUseTexture; 84c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private Bitmap mExpandedTitleTexture; 85c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private Paint mTexturePaint; 86c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private float mTextureAscent; 87c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private float mTextureDescent; 88c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 89c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private float mScale; 90a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private float mCurrentTextSize; 91c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 929995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes private boolean mBoundsChanged; 939995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes 94c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private final TextPaint mTextPaint; 95c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 96c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private Interpolator mPositionInterpolator; 97c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private Interpolator mTextSizeInterpolator; 98c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 9923caabcc1fc96e3756d0c354b49290467080de6aChris Banes private float mCollapsedShadowRadius, mCollapsedShadowDx, mCollapsedShadowDy; 10023caabcc1fc96e3756d0c354b49290467080de6aChris Banes private int mCollapsedShadowColor; 10123caabcc1fc96e3756d0c354b49290467080de6aChris Banes 10223caabcc1fc96e3756d0c354b49290467080de6aChris Banes private float mExpandedShadowRadius, mExpandedShadowDx, mExpandedShadowDy; 10323caabcc1fc96e3756d0c354b49290467080de6aChris Banes private int mExpandedShadowColor; 10423caabcc1fc96e3756d0c354b49290467080de6aChris Banes 105c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes public CollapsingTextHelper(View view) { 106c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mView = view; 107c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 108973218c60005eb672a27b027403c9231d5d21303Chris Banes mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG); 109c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 110c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mCollapsedBounds = new Rect(); 111c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedBounds = new Rect(); 1125c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentBounds = new RectF(); 113c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 114c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 115c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setTextSizeInterpolator(Interpolator interpolator) { 116c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mTextSizeInterpolator = interpolator; 117c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 118c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 119c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 120c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setPositionInterpolator(Interpolator interpolator) { 121c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mPositionInterpolator = interpolator; 122c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 123c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 124c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 125c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setExpandedTextSize(float textSize) { 126c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mExpandedTextSize != textSize) { 127c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedTextSize = textSize; 128c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 129c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 130c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 131c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 132c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setCollapsedTextSize(float textSize) { 133c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mCollapsedTextSize != textSize) { 134c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mCollapsedTextSize = textSize; 135c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 136c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 137c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 138c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 139c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setCollapsedTextColor(int textColor) { 140c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mCollapsedTextColor != textColor) { 141c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mCollapsedTextColor = textColor; 142c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 143c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 144c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 145c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 146c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setExpandedTextColor(int textColor) { 147c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mExpandedTextColor != textColor) { 148c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedTextColor = textColor; 149c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 150c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 151c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 152c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 153c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setExpandedBounds(int left, int top, int right, int bottom) { 1549995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes if (!rectEquals(mExpandedBounds, left, top, right, bottom)) { 1559995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes mExpandedBounds.set(left, top, right, bottom); 1569995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes mBoundsChanged = true; 15766a875e525700de5eed715a52a3329ab5a310d96Chris Banes onBoundsChanged(); 1589995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes } 159c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 160c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 161c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setCollapsedBounds(int left, int top, int right, int bottom) { 1629995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes if (!rectEquals(mCollapsedBounds, left, top, right, bottom)) { 1639995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes mCollapsedBounds.set(left, top, right, bottom); 1649995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes mBoundsChanged = true; 16566a875e525700de5eed715a52a3329ab5a310d96Chris Banes onBoundsChanged(); 1669995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes } 167c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 168c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 16966a875e525700de5eed715a52a3329ab5a310d96Chris Banes void onBoundsChanged() { 17066a875e525700de5eed715a52a3329ab5a310d96Chris Banes mDrawTitle = mCollapsedBounds.width() > 0 && mCollapsedBounds.height() > 0 17166a875e525700de5eed715a52a3329ab5a310d96Chris Banes && mExpandedBounds.width() > 0 && mExpandedBounds.height() > 0; 17266a875e525700de5eed715a52a3329ab5a310d96Chris Banes } 17366a875e525700de5eed715a52a3329ab5a310d96Chris Banes 1745c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes void setExpandedTextGravity(int gravity) { 1755c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes if (mExpandedTextGravity != gravity) { 1765c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedTextGravity = gravity; 177c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 178c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 179c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 180c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 1815c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes int getExpandedTextGravity() { 1825c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes return mExpandedTextGravity; 1835c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes } 184c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 1855c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes void setCollapsedTextGravity(int gravity) { 1865c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes if (mCollapsedTextGravity != gravity) { 1875c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedTextGravity = gravity; 188c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 189c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 190c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 191c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 1925c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes int getCollapsedTextGravity() { 1935c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes return mCollapsedTextGravity; 1945c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes } 1955c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes 196c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setCollapsedTextAppearance(int resId) { 1976759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski TypedArray a = mView.getContext().obtainStyledAttributes(resId, 1986759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance); 1996759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor)) { 2009934230aa2959ee9f1802aa81fd21e25030b0d10Chris Banes mCollapsedTextColor = a.getColor( 2016759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor, 2026759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mCollapsedTextColor); 203c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 2046759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize)) { 205c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mCollapsedTextSize = a.getDimensionPixelSize( 2066759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize, 2076759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski (int) mCollapsedTextSize); 208c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 2096759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mCollapsedShadowColor = a.getInt( 2106759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowColor, 0); 2116759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mCollapsedShadowDx = a.getFloat( 2126759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDx, 0); 2136759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mCollapsedShadowDy = a.getFloat( 2146759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDy, 0); 2156759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mCollapsedShadowRadius = a.getFloat( 2166759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowRadius, 0); 217c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes a.recycle(); 218c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 219d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (Build.VERSION.SDK_INT >= 16) { 220d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mCollapsedTypeface = readFontFamilyTypeface(resId); 221d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 222d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes 223c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 224c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 225c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 226c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setExpandedTextAppearance(int resId) { 2276759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski TypedArray a = mView.getContext().obtainStyledAttributes(resId, 2286759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance); 2296759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor)) { 2309934230aa2959ee9f1802aa81fd21e25030b0d10Chris Banes mExpandedTextColor = a.getColor( 2316759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor, 2326759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mExpandedTextColor); 233c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 2346759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize)) { 235c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedTextSize = a.getDimensionPixelSize( 2366759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize, 2376759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski (int) mExpandedTextSize); 238c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 2396759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mExpandedShadowColor = a.getInt( 2406759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowColor, 0); 2416759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mExpandedShadowDx = a.getFloat( 2426759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDx, 0); 2436759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mExpandedShadowDy = a.getFloat( 2446759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDy, 0); 2456759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski mExpandedShadowRadius = a.getFloat( 2466759b1021d8198ad1d239bb30e5a102b99624bceAdam Lesinski android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowRadius, 0); 247c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes a.recycle(); 248c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 249d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (Build.VERSION.SDK_INT >= 16) { 250d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mExpandedTypeface = readFontFamilyTypeface(resId); 251d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 252d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes 253c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 254c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 255c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 256d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes private Typeface readFontFamilyTypeface(int resId) { 257d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes final TypedArray a = mView.getContext().obtainStyledAttributes(resId, 258d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes new int[]{android.R.attr.fontFamily}); 259d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes try { 260d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes final String family = a.getString(0); 261d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (family != null) { 262d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes return Typeface.create(family, Typeface.NORMAL); 263d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 264d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } finally { 265d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes a.recycle(); 266d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 267d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes return null; 268d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 269d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes 270d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes void setCollapsedTypeface(Typeface typeface) { 271d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (mCollapsedTypeface != typeface) { 272d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mCollapsedTypeface = typeface; 273d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes recalculate(); 274388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes } 275d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 276d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes 277d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes void setExpandedTypeface(Typeface typeface) { 278d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (mExpandedTypeface != typeface) { 279d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mExpandedTypeface = typeface; 280388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes recalculate(); 281388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes } 282388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes } 283388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes 284d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes void setTypefaces(Typeface typeface) { 285d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mCollapsedTypeface = mExpandedTypeface = typeface; 286d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes recalculate(); 287d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 288d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes 289d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes Typeface getCollapsedTypeface() { 290d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes return mCollapsedTypeface != null ? mCollapsedTypeface : Typeface.DEFAULT; 291d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 292d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes 293d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes Typeface getExpandedTypeface() { 294d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes return mExpandedTypeface != null ? mExpandedTypeface : Typeface.DEFAULT; 295388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes } 296388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes 297c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes /** 298c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Set the value indicating the current scroll value. This decides how much of the 299c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * background will be displayed, as well as the title metrics/positioning. 300c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 301c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * A value of {@code 0.0} indicates that the layout is fully expanded. 302c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * A value of {@code 1.0} indicates that the layout is fully collapsed. 303c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */ 304c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setExpansionFraction(float fraction) { 305a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes fraction = MathUtils.constrain(fraction, 0f, 1f); 306a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 307c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (fraction != mExpandedFraction) { 308c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedFraction = fraction; 3095c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes calculateCurrentOffsets(); 310c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 311c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 312c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 313c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float getExpansionFraction() { 314c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return mExpandedFraction; 315c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 316c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 317c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float getCollapsedTextSize() { 318c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return mCollapsedTextSize; 319c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 320c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 321c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float getExpandedTextSize() { 322c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return mExpandedTextSize; 323c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 324c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 3255c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private void calculateCurrentOffsets() { 32623caabcc1fc96e3756d0c354b49290467080de6aChris Banes calculateOffsets(mExpandedFraction); 32723caabcc1fc96e3756d0c354b49290467080de6aChris Banes } 328c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 32923caabcc1fc96e3756d0c354b49290467080de6aChris Banes private void calculateOffsets(final float fraction) { 3305c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes interpolateBounds(fraction); 3315c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentDrawX = lerp(mExpandedDrawX, mCollapsedDrawX, fraction, 3325c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mPositionInterpolator); 3335c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentDrawY = lerp(mExpandedDrawY, mCollapsedDrawY, fraction, 3345c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mPositionInterpolator); 3355c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes 3365c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes setInterpolatedTextSize(lerp(mExpandedTextSize, mCollapsedTextSize, 337c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes fraction, mTextSizeInterpolator)); 338c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 339c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mCollapsedTextColor != mExpandedTextColor) { 340c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // If the collapsed and expanded text colors are different, blend them based on the 341c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // fraction 342c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mTextPaint.setColor(blendColors(mExpandedTextColor, mCollapsedTextColor, fraction)); 343c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } else { 344c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mTextPaint.setColor(mCollapsedTextColor); 345c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 346c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 34723caabcc1fc96e3756d0c354b49290467080de6aChris Banes mTextPaint.setShadowLayer( 34823caabcc1fc96e3756d0c354b49290467080de6aChris Banes lerp(mExpandedShadowRadius, mCollapsedShadowRadius, fraction, null), 34923caabcc1fc96e3756d0c354b49290467080de6aChris Banes lerp(mExpandedShadowDx, mCollapsedShadowDx, fraction, null), 35023caabcc1fc96e3756d0c354b49290467080de6aChris Banes lerp(mExpandedShadowDy, mCollapsedShadowDy, fraction, null), 35123caabcc1fc96e3756d0c354b49290467080de6aChris Banes blendColors(mExpandedShadowColor, mCollapsedShadowColor, fraction)); 35223caabcc1fc96e3756d0c354b49290467080de6aChris Banes 353c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes ViewCompat.postInvalidateOnAnimation(mView); 354c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 355c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 3565c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private void calculateBaseOffsets() { 35737430e835e22a791b83b01befab44ead852bf555Chris Banes final float currentTextSize = mCurrentTextSize; 35837430e835e22a791b83b01befab44ead852bf555Chris Banes 359c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // We then calculate the collapsed text size, using the same logic 36037430e835e22a791b83b01befab44ead852bf555Chris Banes calculateUsingTextSize(mCollapsedTextSize); 3615c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes float width = mTextToDraw != null ? 3625c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0; 3635c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes final int collapsedAbsGravity = GravityCompat.getAbsoluteGravity(mCollapsedTextGravity, 3645c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mIsRtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR); 3655c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes switch (collapsedAbsGravity & Gravity.VERTICAL_GRAVITY_MASK) { 366c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes case Gravity.BOTTOM: 3675c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedDrawY = mCollapsedBounds.bottom; 368c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes break; 369c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes case Gravity.TOP: 3705c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedDrawY = mCollapsedBounds.top - mTextPaint.ascent(); 371c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes break; 372c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes case Gravity.CENTER_VERTICAL: 373c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes default: 374c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float textHeight = mTextPaint.descent() - mTextPaint.ascent(); 375c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float textOffset = (textHeight / 2) - mTextPaint.descent(); 3765c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedDrawY = mCollapsedBounds.centerY() + textOffset; 3775c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes break; 3785c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes } 379f828412cf077314f63e9d989c889f69275a28b19Chris Banes switch (collapsedAbsGravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK) { 3805c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes case Gravity.CENTER_HORIZONTAL: 3815c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedDrawX = mCollapsedBounds.centerX() - (width / 2); 3825c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes break; 3835c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes case Gravity.RIGHT: 3845c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedDrawX = mCollapsedBounds.right - width; 3855c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes break; 3865c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes case Gravity.LEFT: 3875c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes default: 3885c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCollapsedDrawX = mCollapsedBounds.left; 389c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes break; 390c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 391c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 39237430e835e22a791b83b01befab44ead852bf555Chris Banes calculateUsingTextSize(mExpandedTextSize); 3935c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes width = mTextToDraw != null 3945c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes ? mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0; 3955c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes final int expandedAbsGravity = GravityCompat.getAbsoluteGravity(mExpandedTextGravity, 3965c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mIsRtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR); 3975c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes switch (expandedAbsGravity & Gravity.VERTICAL_GRAVITY_MASK) { 398c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes case Gravity.BOTTOM: 3995c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedDrawY = mExpandedBounds.bottom; 400c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes break; 401c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes case Gravity.TOP: 4025c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedDrawY = mExpandedBounds.top - mTextPaint.ascent(); 403c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes break; 404c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes case Gravity.CENTER_VERTICAL: 405c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes default: 406c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float textHeight = mTextPaint.descent() - mTextPaint.ascent(); 407c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float textOffset = (textHeight / 2) - mTextPaint.descent(); 4085c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedDrawY = mExpandedBounds.centerY() + textOffset; 4095c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes break; 4105c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes } 411f828412cf077314f63e9d989c889f69275a28b19Chris Banes switch (expandedAbsGravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK) { 4125c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes case Gravity.CENTER_HORIZONTAL: 4135c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedDrawX = mExpandedBounds.centerX() - (width / 2); 4145c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes break; 4155c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes case Gravity.RIGHT: 4165c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedDrawX = mExpandedBounds.right - width; 4175c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes break; 4185c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes case Gravity.LEFT: 4195c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes default: 4205c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mExpandedDrawX = mExpandedBounds.left; 421c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes break; 422c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 423c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 424c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // The bounds have changed so we need to clear the texture 425c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes clearTexture(); 42637430e835e22a791b83b01befab44ead852bf555Chris Banes // Now reset the text size back to the original 42737430e835e22a791b83b01befab44ead852bf555Chris Banes setInterpolatedTextSize(currentTextSize); 428c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 429c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 4305c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private void interpolateBounds(float fraction) { 4315c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentBounds.left = lerp(mExpandedBounds.left, mCollapsedBounds.left, 4325c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes fraction, mPositionInterpolator); 4335c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentBounds.top = lerp(mExpandedDrawY, mCollapsedDrawY, 4345c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes fraction, mPositionInterpolator); 4355c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentBounds.right = lerp(mExpandedBounds.right, mCollapsedBounds.right, 4365c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes fraction, mPositionInterpolator); 4375c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mCurrentBounds.bottom = lerp(mExpandedBounds.bottom, mCollapsedBounds.bottom, 4385c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes fraction, mPositionInterpolator); 4395c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes } 4405c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes 441c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes public void draw(Canvas canvas) { 442c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final int saveCount = canvas.save(); 443c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 44466a875e525700de5eed715a52a3329ab5a310d96Chris Banes if (mTextToDraw != null && mDrawTitle) { 4455c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes float x = mCurrentDrawX; 4465c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes float y = mCurrentDrawY; 447c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 448c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final boolean drawTexture = mUseTexture && mExpandedTitleTexture != null; 449c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 450c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final float ascent; 451c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final float descent; 452c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (drawTexture) { 453c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes ascent = mTextureAscent * mScale; 454c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes descent = mTextureDescent * mScale; 455c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } else { 456c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes ascent = mTextPaint.ascent() * mScale; 457c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes descent = mTextPaint.descent() * mScale; 458c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 459c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 460c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (DEBUG_DRAW) { 461c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // Just a debug tool, which drawn a Magneta rect in the text bounds 4625c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes canvas.drawRect(mCurrentBounds.left, y + ascent, mCurrentBounds.right, y + descent, 463c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes DEBUG_DRAW_PAINT); 464c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 465c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 466c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (drawTexture) { 467c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes y += ascent; 468c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 469c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 470c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mScale != 1f) { 471c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes canvas.scale(mScale, mScale, x, y); 472c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 473c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 474c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (drawTexture) { 475c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // If we should use a texture, draw it instead of text 476c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes canvas.drawBitmap(mExpandedTitleTexture, x, y, mTexturePaint); 477c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } else { 478c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes canvas.drawText(mTextToDraw, 0, mTextToDraw.length(), x, y, mTextPaint); 479c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 480c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 481c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 482c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes canvas.restoreToCount(saveCount); 483c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 484c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 485fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes private boolean calculateIsRtl(CharSequence text) { 486fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes final boolean defaultIsRtl = ViewCompat.getLayoutDirection(mView) 487fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes == ViewCompat.LAYOUT_DIRECTION_RTL; 488fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes return (defaultIsRtl 489fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL 490fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes : TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length()); 491fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes } 492fef6dbf449d6e2992872a725170c5fcb4aa16975Chris Banes 49337430e835e22a791b83b01befab44ead852bf555Chris Banes private void setInterpolatedTextSize(float textSize) { 49437430e835e22a791b83b01befab44ead852bf555Chris Banes calculateUsingTextSize(textSize); 49537430e835e22a791b83b01befab44ead852bf555Chris Banes 49637430e835e22a791b83b01befab44ead852bf555Chris Banes // Use our texture if the scale isn't 1.0 49737430e835e22a791b83b01befab44ead852bf555Chris Banes mUseTexture = USE_SCALING_TEXTURE && mScale != 1f; 49837430e835e22a791b83b01befab44ead852bf555Chris Banes 49937430e835e22a791b83b01befab44ead852bf555Chris Banes if (mUseTexture) { 50037430e835e22a791b83b01befab44ead852bf555Chris Banes // Make sure we have an expanded texture if needed 50137430e835e22a791b83b01befab44ead852bf555Chris Banes ensureExpandedTexture(); 50237430e835e22a791b83b01befab44ead852bf555Chris Banes } 50337430e835e22a791b83b01befab44ead852bf555Chris Banes 50437430e835e22a791b83b01befab44ead852bf555Chris Banes ViewCompat.postInvalidateOnAnimation(mView); 50537430e835e22a791b83b01befab44ead852bf555Chris Banes } 50637430e835e22a791b83b01befab44ead852bf555Chris Banes 50737430e835e22a791b83b01befab44ead852bf555Chris Banes private void calculateUsingTextSize(final float textSize) { 508c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mText == null) return; 509c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 510a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes final float availableWidth; 511a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes final float newTextSize; 512a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes boolean updateDrawText = false; 513c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 514c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (isClose(textSize, mCollapsedTextSize)) { 515c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes availableWidth = mCollapsedBounds.width(); 516a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes newTextSize = mCollapsedTextSize; 517a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mScale = 1f; 518d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (mCurrentTypeface != mCollapsedTypeface) { 519d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mCurrentTypeface = mCollapsedTypeface; 520d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes updateDrawText = true; 521d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 522c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } else { 523a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes availableWidth = mExpandedBounds.width(); 524a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes newTextSize = mExpandedTextSize; 525d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes if (mCurrentTypeface != mExpandedTypeface) { 526d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mCurrentTypeface = mExpandedTypeface; 527d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes updateDrawText = true; 528d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes } 529c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 530c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (isClose(textSize, mExpandedTextSize)) { 531c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // If we're close to the expanded text size, snap to it and use a scale of 1 532c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mScale = 1f; 533c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } else { 534c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // Else, we'll scale down from the expanded text size 535c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mScale = textSize / mExpandedTextSize; 536c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 537c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 538c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 539a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes if (availableWidth > 0) { 540d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged || updateDrawText; 541a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mCurrentTextSize = newTextSize; 5429995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes mBoundsChanged = false; 543a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 544a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 545a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes if (mTextToDraw == null || updateDrawText) { 546a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mTextPaint.setTextSize(mCurrentTextSize); 547d29e79fa09f428c510d1d9ca758dbda35a323f71Chris Banes mTextPaint.setTypeface(mCurrentTypeface); 548973218c60005eb672a27b027403c9231d5d21303Chris Banes // Use linear text scaling if we're scaling the canvas 549973218c60005eb672a27b027403c9231d5d21303Chris Banes mTextPaint.setLinearText(mScale != 1f); 550a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 551c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // If we don't currently have text to draw, or the text size has changed, ellipsize... 552c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final CharSequence title = TextUtils.ellipsize(mText, mTextPaint, 553c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes availableWidth, TextUtils.TruncateAt.END); 55437430e835e22a791b83b01befab44ead852bf555Chris Banes if (!TextUtils.equals(title, mTextToDraw)) { 555c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mTextToDraw = title; 55637430e835e22a791b83b01befab44ead852bf555Chris Banes mIsRtl = calculateIsRtl(mTextToDraw); 557c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 558c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 559c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 560c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 561c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private void ensureExpandedTexture() { 562c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mExpandedTitleTexture != null || mExpandedBounds.isEmpty() 563c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes || TextUtils.isEmpty(mTextToDraw)) { 564c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return; 565c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 566c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 56723caabcc1fc96e3756d0c354b49290467080de6aChris Banes calculateOffsets(0f); 5685c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mTextureAscent = mTextPaint.ascent(); 5695c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mTextureDescent = mTextPaint.descent(); 570c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 571c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final int w = Math.round(mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length())); 5725c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes final int h = Math.round(mTextureDescent - mTextureAscent); 573c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 5746fa3c92dcaf584ac56bff4c0b52b7b1ac379592eChris Banes if (w <= 0 || h <= 0) { 575c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return; // If the width or height are 0, return 576c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 577c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 578c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedTitleTexture = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 579c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 580c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes Canvas c = new Canvas(mExpandedTitleTexture); 581c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes c.drawText(mTextToDraw, 0, mTextToDraw.length(), 0, h - mTextPaint.descent(), mTextPaint); 582c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 583c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mTexturePaint == null) { 584c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // Make sure we have a paint 5855c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes mTexturePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 586c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 587c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 588c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 5891bf6093c6dab532bc57c75767470afa3cbbe0384Chris Banes public void recalculate() { 5901bf6093c6dab532bc57c75767470afa3cbbe0384Chris Banes if (mView.getHeight() > 0 && mView.getWidth() > 0) { 591c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // If we've already been laid out, calculate everything now otherwise we'll wait 592c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes // until a layout 5935c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes calculateBaseOffsets(); 5945c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes calculateCurrentOffsets(); 595c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 596c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 597c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 598c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes /** 599c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Set the title to display 600c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 601c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * @param text 602c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */ 603c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes void setText(CharSequence text) { 604c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (text == null || !text.equals(mText)) { 605c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mText = text; 606d9d3addb4628537f68348d40346765b7f407cf79Chris Banes mTextToDraw = null; 607c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes clearTexture(); 608c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes recalculate(); 609c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 610c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 611c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 612c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes CharSequence getText() { 613c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return mText; 614c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 615c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 616c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private void clearTexture() { 617c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (mExpandedTitleTexture != null) { 618c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedTitleTexture.recycle(); 619c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes mExpandedTitleTexture = null; 620c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 621c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 622c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 623c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes /** 624c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Returns true if {@code value} is 'close' to it's closest decimal value. Close is currently 625c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * defined as it's difference being < 0.001. 626c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */ 627c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private static boolean isClose(float value, float targetValue) { 628c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return Math.abs(value - targetValue) < 0.001f; 629c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 630c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 631c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes int getExpandedTextColor() { 632c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return mExpandedTextColor; 633c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 634c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 635c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes int getCollapsedTextColor() { 636c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return mCollapsedTextColor; 637c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 638c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 639c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes /** 640c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Blend {@code color1} and {@code color2} using the given ratio. 641c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 642c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * @param ratio of which to blend. 0.0 will return {@code color1}, 0.5 will give an even blend, 643c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * 1.0 will return {@code color2}. 644c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */ 645c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes private static int blendColors(int color1, int color2, float ratio) { 646c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes final float inverseRatio = 1f - ratio; 647c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float a = (Color.alpha(color1) * inverseRatio) + (Color.alpha(color2) * ratio); 648c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float r = (Color.red(color1) * inverseRatio) + (Color.red(color2) * ratio); 649c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float g = (Color.green(color1) * inverseRatio) + (Color.green(color2) * ratio); 650c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes float b = (Color.blue(color1) * inverseRatio) + (Color.blue(color2) * ratio); 651c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return Color.argb((int) a, (int) r, (int) g, (int) b); 652c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 653c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes 6545c7d7bbceeaebc46dc2e4b2135cc330414f716d4Chris Banes private static float lerp(float startValue, float endValue, float fraction, 655c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes Interpolator interpolator) { 656c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes if (interpolator != null) { 657c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes fraction = interpolator.getInterpolation(fraction); 658c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 659c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes return AnimationUtils.lerp(startValue, endValue, fraction); 660c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes } 6619995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes 6629995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes private static boolean rectEquals(Rect r, int left, int top, int right, int bottom) { 6639995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes return !(r.left != left || r.top != top || r.right != right || r.bottom != bottom); 6649995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes } 665c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes} 666