FloatingActionButton.java revision 1711e8729c1b901b73f530e87b7c9cc9370f33be
19840efe3dbdc7026521da8576574c55120782f6cChris Banes/* 29840efe3dbdc7026521da8576574c55120782f6cChris Banes * Copyright (C) 2015 The Android Open Source Project 39840efe3dbdc7026521da8576574c55120782f6cChris Banes * 49840efe3dbdc7026521da8576574c55120782f6cChris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 59840efe3dbdc7026521da8576574c55120782f6cChris Banes * you may not use this file except in compliance with the License. 69840efe3dbdc7026521da8576574c55120782f6cChris Banes * You may obtain a copy of the License at 79840efe3dbdc7026521da8576574c55120782f6cChris Banes * 89840efe3dbdc7026521da8576574c55120782f6cChris Banes * http://www.apache.org/licenses/LICENSE-2.0 99840efe3dbdc7026521da8576574c55120782f6cChris Banes * 109840efe3dbdc7026521da8576574c55120782f6cChris Banes * Unless required by applicable law or agreed to in writing, software 119840efe3dbdc7026521da8576574c55120782f6cChris Banes * distributed under the License is distributed on an "AS IS" BASIS, 129840efe3dbdc7026521da8576574c55120782f6cChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139840efe3dbdc7026521da8576574c55120782f6cChris Banes * See the License for the specific language governing permissions and 149840efe3dbdc7026521da8576574c55120782f6cChris Banes * limitations under the License. 159840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 169840efe3dbdc7026521da8576574c55120782f6cChris Banes 179840efe3dbdc7026521da8576574c55120782f6cChris Banespackage android.support.design.widget; 189840efe3dbdc7026521da8576574c55120782f6cChris Banes 199840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.annotation.TargetApi; 209840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.content.Context; 219840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.content.res.ColorStateList; 229840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.content.res.TypedArray; 239840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.PorterDuff; 249840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.Rect; 259840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.drawable.Drawable; 269840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.os.Build; 277a13c8489daca7915623dd673df49de2d1a0bf30Chris Banesimport android.support.annotation.ColorInt; 281711e8729c1b901b73f530e87b7c9cc9370f33beChris Banesimport android.support.annotation.DrawableRes; 29d9cbe69a6661315238d856abc22578d03666f63bChris Banesimport android.support.annotation.NonNull; 309840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.support.annotation.Nullable; 319840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.support.design.R; 320ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Weiimport android.support.design.widget.FloatingActionButtonImpl.InternalVisibilityChangedListener; 33b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewCompat; 341711e8729c1b901b73f530e87b7c9cc9370f33beChris Banesimport android.support.v7.widget.AppCompatDrawableManager; 351711e8729c1b901b73f530e87b7c9cc9370f33beChris Banesimport android.support.v7.widget.AppCompatImageHelper; 369840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.util.AttributeSet; 37097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banesimport android.util.Log; 3814d064edb3e4a16a3b90a4a850560177bea1e60dChris Banesimport android.view.View; 399840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.widget.ImageView; 409840efe3dbdc7026521da8576574c55120782f6cChris Banes 41a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport java.util.List; 42b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 439840efe3dbdc7026521da8576574c55120782f6cChris Banes/** 449840efe3dbdc7026521da8576574c55120782f6cChris Banes * Floating action buttons are used for a special type of promoted action. They are distinguished 4514d064edb3e4a16a3b90a4a850560177bea1e60dChris Banes * by a circled icon floating above the UI and have special motion behaviors related to morphing, 469840efe3dbdc7026521da8576574c55120782f6cChris Banes * launching, and the transferring anchor point. 479840efe3dbdc7026521da8576574c55120782f6cChris Banes * 489fb154338a62edc2c57dc036895199d6f1769400Chris Banes * <p>Floating action buttons come in two sizes: the default and the mini. The size can be 499fb154338a62edc2c57dc036895199d6f1769400Chris Banes * controlled with the {@code fabSize} attribute.</p> 509fb154338a62edc2c57dc036895199d6f1769400Chris Banes * 519fb154338a62edc2c57dc036895199d6f1769400Chris Banes * <p>As this class descends from {@link ImageView}, you can control the icon which is displayed 529fb154338a62edc2c57dc036895199d6f1769400Chris Banes * via {@link #setImageDrawable(Drawable)}.</p> 539fb154338a62edc2c57dc036895199d6f1769400Chris Banes * 549fb154338a62edc2c57dc036895199d6f1769400Chris Banes * <p>The background color of this view defaults to the your theme's {@code colorAccent}. If you 559fb154338a62edc2c57dc036895199d6f1769400Chris Banes * wish to change this at runtime then you can do so via 569fb154338a62edc2c57dc036895199d6f1769400Chris Banes * {@link #setBackgroundTintList(ColorStateList)}.</p> 579fb154338a62edc2c57dc036895199d6f1769400Chris Banes * 589fb154338a62edc2c57dc036895199d6f1769400Chris Banes * @attr ref android.support.design.R.styleable#FloatingActionButton_fabSize 599840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 60b7f9224b1495db47eb8fd813b5912250e900770aChris Banes@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class) 61fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banespublic class FloatingActionButton extends VisibilityAwareImageButton { 629840efe3dbdc7026521da8576574c55120782f6cChris Banes 63097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes private static final String LOG_TAG = "FloatingActionButton"; 64097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes 650ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei /** 660ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * Callback to be invoked when the visibility of a FloatingActionButton changes. 670ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei */ 680ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public abstract static class OnVisibilityChangedListener { 690ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei /** 700ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * Called when a FloatingActionButton has been 710ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * {@link #show(OnVisibilityChangedListener) shown}. 720ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * 730ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * @param fab the FloatingActionButton that was shown. 740ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei */ 750ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void onShown(FloatingActionButton fab) {} 760ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 770ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei /** 780ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * Called when a FloatingActionButton has been 790ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * {@link #hide(OnVisibilityChangedListener) hidden}. 800ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * 810ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * @param fab the FloatingActionButton that was hidden. 820ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei */ 830ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void onHidden(FloatingActionButton fab) {} 840ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 850ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 869840efe3dbdc7026521da8576574c55120782f6cChris Banes // These values must match those in the attrs declaration 879840efe3dbdc7026521da8576574c55120782f6cChris Banes private static final int SIZE_MINI = 1; 889840efe3dbdc7026521da8576574c55120782f6cChris Banes private static final int SIZE_NORMAL = 0; 899840efe3dbdc7026521da8576574c55120782f6cChris Banes 909840efe3dbdc7026521da8576574c55120782f6cChris Banes private ColorStateList mBackgroundTint; 919840efe3dbdc7026521da8576574c55120782f6cChris Banes private PorterDuff.Mode mBackgroundTintMode; 929840efe3dbdc7026521da8576574c55120782f6cChris Banes 93cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes private int mBorderWidth; 949840efe3dbdc7026521da8576574c55120782f6cChris Banes private int mRippleColor; 959840efe3dbdc7026521da8576574c55120782f6cChris Banes private int mSize; 96d9cbe69a6661315238d856abc22578d03666f63bChris Banes private int mImagePadding; 979840efe3dbdc7026521da8576574c55120782f6cChris Banes 986d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes private boolean mCompatPadding; 99cdc736866534c604c4015c78371ade52bb6d52dfChris Banes private final Rect mShadowPadding = new Rect(); 1009840efe3dbdc7026521da8576574c55120782f6cChris Banes 1011711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes private AppCompatImageHelper mImageHelper; 1021711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes 103d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes private FloatingActionButtonImpl mImpl; 1049840efe3dbdc7026521da8576574c55120782f6cChris Banes 1059840efe3dbdc7026521da8576574c55120782f6cChris Banes public FloatingActionButton(Context context) { 1069840efe3dbdc7026521da8576574c55120782f6cChris Banes this(context, null); 1079840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1089840efe3dbdc7026521da8576574c55120782f6cChris Banes 1099840efe3dbdc7026521da8576574c55120782f6cChris Banes public FloatingActionButton(Context context, AttributeSet attrs) { 1109840efe3dbdc7026521da8576574c55120782f6cChris Banes this(context, attrs, 0); 1119840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1129840efe3dbdc7026521da8576574c55120782f6cChris Banes 1139840efe3dbdc7026521da8576574c55120782f6cChris Banes public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { 1149840efe3dbdc7026521da8576574c55120782f6cChris Banes super(context, attrs, defStyleAttr); 1159840efe3dbdc7026521da8576574c55120782f6cChris Banes 116809bb62055ad42b88f3a69308be222801b89fbd9Chris Banes ThemeUtils.checkAppCompatTheme(context); 117809bb62055ad42b88f3a69308be222801b89fbd9Chris Banes 1189840efe3dbdc7026521da8576574c55120782f6cChris Banes TypedArray a = context.obtainStyledAttributes(attrs, 1199840efe3dbdc7026521da8576574c55120782f6cChris Banes R.styleable.FloatingActionButton, defStyleAttr, 1209840efe3dbdc7026521da8576574c55120782f6cChris Banes R.style.Widget_Design_FloatingActionButton); 1219840efe3dbdc7026521da8576574c55120782f6cChris Banes mBackgroundTint = a.getColorStateList(R.styleable.FloatingActionButton_backgroundTint); 1229840efe3dbdc7026521da8576574c55120782f6cChris Banes mBackgroundTintMode = parseTintMode(a.getInt( 1239840efe3dbdc7026521da8576574c55120782f6cChris Banes R.styleable.FloatingActionButton_backgroundTintMode, -1), null); 1249840efe3dbdc7026521da8576574c55120782f6cChris Banes mRippleColor = a.getColor(R.styleable.FloatingActionButton_rippleColor, 0); 1259840efe3dbdc7026521da8576574c55120782f6cChris Banes mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, SIZE_NORMAL); 126cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes mBorderWidth = a.getDimensionPixelSize(R.styleable.FloatingActionButton_borderWidth, 0); 1279840efe3dbdc7026521da8576574c55120782f6cChris Banes final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f); 1289840efe3dbdc7026521da8576574c55120782f6cChris Banes final float pressedTranslationZ = a.getDimension( 1299840efe3dbdc7026521da8576574c55120782f6cChris Banes R.styleable.FloatingActionButton_pressedTranslationZ, 0f); 1306d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes mCompatPadding = a.getBoolean(R.styleable.FloatingActionButton_useCompatPadding, false); 1319840efe3dbdc7026521da8576574c55120782f6cChris Banes a.recycle(); 1329840efe3dbdc7026521da8576574c55120782f6cChris Banes 1331711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes mImageHelper = new AppCompatImageHelper(this, AppCompatDrawableManager.get()); 1341711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes mImageHelper.loadFromAttributes(attrs, defStyleAttr); 1351711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes 136d9cbe69a6661315238d856abc22578d03666f63bChris Banes final int maxImageSize = (int) getResources().getDimension(R.dimen.design_fab_image_size); 137d9cbe69a6661315238d856abc22578d03666f63bChris Banes mImagePadding = (getSizeDimension() - maxImageSize) / 2; 1389840efe3dbdc7026521da8576574c55120782f6cChris Banes 139d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode, 140097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes mRippleColor, mBorderWidth); 141d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setElevation(elevation); 142d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setPressedTranslationZ(pressedTranslationZ); 143d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().updatePadding(); 1449840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1459840efe3dbdc7026521da8576574c55120782f6cChris Banes 1469840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 1479840efe3dbdc7026521da8576574c55120782f6cChris Banes protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1489840efe3dbdc7026521da8576574c55120782f6cChris Banes final int preferredSize = getSizeDimension(); 1499840efe3dbdc7026521da8576574c55120782f6cChris Banes 1509840efe3dbdc7026521da8576574c55120782f6cChris Banes final int w = resolveAdjustedSize(preferredSize, widthMeasureSpec); 1519840efe3dbdc7026521da8576574c55120782f6cChris Banes final int h = resolveAdjustedSize(preferredSize, heightMeasureSpec); 1529840efe3dbdc7026521da8576574c55120782f6cChris Banes 1539840efe3dbdc7026521da8576574c55120782f6cChris Banes // As we want to stay circular, we set both dimensions to be the 1549840efe3dbdc7026521da8576574c55120782f6cChris Banes // smallest resolved dimension 1559840efe3dbdc7026521da8576574c55120782f6cChris Banes final int d = Math.min(w, h); 1569840efe3dbdc7026521da8576574c55120782f6cChris Banes 1579840efe3dbdc7026521da8576574c55120782f6cChris Banes // We add the shadow's padding to the measured dimension 1589840efe3dbdc7026521da8576574c55120782f6cChris Banes setMeasuredDimension( 1599840efe3dbdc7026521da8576574c55120782f6cChris Banes d + mShadowPadding.left + mShadowPadding.right, 1609840efe3dbdc7026521da8576574c55120782f6cChris Banes d + mShadowPadding.top + mShadowPadding.bottom); 1619840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1629840efe3dbdc7026521da8576574c55120782f6cChris Banes 1639840efe3dbdc7026521da8576574c55120782f6cChris Banes /** 1649840efe3dbdc7026521da8576574c55120782f6cChris Banes * Set the ripple color for this {@link FloatingActionButton}. 1659840efe3dbdc7026521da8576574c55120782f6cChris Banes * <p> 1669840efe3dbdc7026521da8576574c55120782f6cChris Banes * When running on devices with KitKat or below, we draw a fill rather than a ripple. 1679840efe3dbdc7026521da8576574c55120782f6cChris Banes * 1689840efe3dbdc7026521da8576574c55120782f6cChris Banes * @param color ARGB color to use for the ripple. 1696d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 1706d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @attr ref android.support.design.R.styleable#FloatingActionButton_rippleColor 1719840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 1727a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes public void setRippleColor(@ColorInt int color) { 1739840efe3dbdc7026521da8576574c55120782f6cChris Banes if (mRippleColor != color) { 1749840efe3dbdc7026521da8576574c55120782f6cChris Banes mRippleColor = color; 175d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setRippleColor(color); 1769840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1779840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1789840efe3dbdc7026521da8576574c55120782f6cChris Banes 1799840efe3dbdc7026521da8576574c55120782f6cChris Banes /** 1809840efe3dbdc7026521da8576574c55120782f6cChris Banes * Return the tint applied to the background drawable, if specified. 1819840efe3dbdc7026521da8576574c55120782f6cChris Banes * 1829840efe3dbdc7026521da8576574c55120782f6cChris Banes * @return the tint applied to the background drawable 1839840efe3dbdc7026521da8576574c55120782f6cChris Banes * @see #setBackgroundTintList(ColorStateList) 1849840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 1859840efe3dbdc7026521da8576574c55120782f6cChris Banes @Nullable 1869840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 1879840efe3dbdc7026521da8576574c55120782f6cChris Banes public ColorStateList getBackgroundTintList() { 1889840efe3dbdc7026521da8576574c55120782f6cChris Banes return mBackgroundTint; 1899840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1909840efe3dbdc7026521da8576574c55120782f6cChris Banes 1919840efe3dbdc7026521da8576574c55120782f6cChris Banes /** 1929840efe3dbdc7026521da8576574c55120782f6cChris Banes * Applies a tint to the background drawable. Does not modify the current tint 1939840efe3dbdc7026521da8576574c55120782f6cChris Banes * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 1949840efe3dbdc7026521da8576574c55120782f6cChris Banes * 1959840efe3dbdc7026521da8576574c55120782f6cChris Banes * @param tint the tint to apply, may be {@code null} to clear tint 1969840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 1979840efe3dbdc7026521da8576574c55120782f6cChris Banes public void setBackgroundTintList(@Nullable ColorStateList tint) { 1987a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes if (mBackgroundTint != tint) { 1997a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes mBackgroundTint = tint; 200d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setBackgroundTintList(tint); 2017a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes } 2029840efe3dbdc7026521da8576574c55120782f6cChris Banes } 2039840efe3dbdc7026521da8576574c55120782f6cChris Banes 2049840efe3dbdc7026521da8576574c55120782f6cChris Banes /** 2059840efe3dbdc7026521da8576574c55120782f6cChris Banes * Return the blending mode used to apply the tint to the background 2069840efe3dbdc7026521da8576574c55120782f6cChris Banes * drawable, if specified. 2079840efe3dbdc7026521da8576574c55120782f6cChris Banes * 2089840efe3dbdc7026521da8576574c55120782f6cChris Banes * @return the blending mode used to apply the tint to the background 2099840efe3dbdc7026521da8576574c55120782f6cChris Banes * drawable 2109840efe3dbdc7026521da8576574c55120782f6cChris Banes * @see #setBackgroundTintMode(PorterDuff.Mode) 2119840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 2129840efe3dbdc7026521da8576574c55120782f6cChris Banes @Nullable 2139840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 2149840efe3dbdc7026521da8576574c55120782f6cChris Banes public PorterDuff.Mode getBackgroundTintMode() { 2159840efe3dbdc7026521da8576574c55120782f6cChris Banes return mBackgroundTintMode; 2169840efe3dbdc7026521da8576574c55120782f6cChris Banes } 2179840efe3dbdc7026521da8576574c55120782f6cChris Banes 2189840efe3dbdc7026521da8576574c55120782f6cChris Banes /** 2199840efe3dbdc7026521da8576574c55120782f6cChris Banes * Specifies the blending mode used to apply the tint specified by 2209840efe3dbdc7026521da8576574c55120782f6cChris Banes * {@link #setBackgroundTintList(ColorStateList)}} to the background 2219840efe3dbdc7026521da8576574c55120782f6cChris Banes * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 2229840efe3dbdc7026521da8576574c55120782f6cChris Banes * 2239840efe3dbdc7026521da8576574c55120782f6cChris Banes * @param tintMode the blending mode used to apply the tint, may be 2249840efe3dbdc7026521da8576574c55120782f6cChris Banes * {@code null} to clear tint 2259840efe3dbdc7026521da8576574c55120782f6cChris Banes */ 2269840efe3dbdc7026521da8576574c55120782f6cChris Banes public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 2277a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes if (mBackgroundTintMode != tintMode) { 2287a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes mBackgroundTintMode = tintMode; 229d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setBackgroundTintMode(tintMode); 2307a13c8489daca7915623dd673df49de2d1a0bf30Chris Banes } 2319840efe3dbdc7026521da8576574c55120782f6cChris Banes } 2329840efe3dbdc7026521da8576574c55120782f6cChris Banes 2339840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 234097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes public void setBackgroundDrawable(Drawable background) { 235097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes Log.i(LOG_TAG, "Setting a custom background is not supported."); 236097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes } 237097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes 238097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes @Override 239097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes public void setBackgroundResource(int resid) { 240097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes Log.i(LOG_TAG, "Setting a custom background is not supported."); 241097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes } 242097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes 243097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes @Override 244097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes public void setBackgroundColor(int color) { 245097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes Log.i(LOG_TAG, "Setting a custom background is not supported."); 246be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 247be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 2481711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes @Override 2491711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes public void setImageResource(@DrawableRes int resId) { 2501711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes // Intercept this call and instead retrieve the Drawable via the image helper 2511711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes mImageHelper.setImageResource(resId); 2521711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes } 2531711e8729c1b901b73f530e87b7c9cc9370f33beChris Banes 254be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes /** 255be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes * Shows the button. 2568c05e5f52fbc790b745e768398d9e69d6b9d9ee1Chris Banes * <p>This method will animate the button show if the view has already been laid out.</p> 257be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes */ 258be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes public void show() { 259fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes show(null); 2600ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 2610ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 2620ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei /** 2630ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * Shows the button. 2648c05e5f52fbc790b745e768398d9e69d6b9d9ee1Chris Banes * <p>This method will animate the button show if the view has already been laid out.</p> 2650ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * 2660ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * @param listener the listener to notify when this view is shown 2670ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei */ 2680ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void show(@Nullable final OnVisibilityChangedListener listener) { 269fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes show(listener, true); 270fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes } 271fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes 272fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes private void show(OnVisibilityChangedListener listener, boolean fromUser) { 273d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().show(wrapOnVisibilityChangedListener(listener), fromUser); 274be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 275be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 276be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes /** 277be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes * Hides the button. 278be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes * <p>This method will animate the button hide if the view has already been laid out.</p> 279be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes */ 280be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes public void hide() { 281fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes hide(null); 2820ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 2830ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 2840ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei /** 2850ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * Hides the button. 2860ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * <p>This method will animate the button hide if the view has already been laid out.</p> 2870ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * 2880ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei * @param listener the listener to notify when this view is hidden 2890ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei */ 2900ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void hide(@Nullable OnVisibilityChangedListener listener) { 291fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes hide(listener, true); 292fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes } 293fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes 294fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes private void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) { 295d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().hide(wrapOnVisibilityChangedListener(listener), fromUser); 2960ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 2970ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 2986d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes /** 2996d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * Set whether FloatingActionButton should add inner padding on platforms Lollipop and after, 3006d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * to ensure consistent dimensions on all platforms. 3016d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 3026d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @param useCompatPadding true if FloatingActionButton is adding inner padding on platforms 3036d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * Lollipop and after, to ensure consistent dimensions on all platforms. 3046d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 3056d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding 3066d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @see #getUseCompatPadding() 3076d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes */ 3086d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes public void setUseCompatPadding(boolean useCompatPadding) { 3096d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes if (mCompatPadding != useCompatPadding) { 3106d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes mCompatPadding = useCompatPadding; 311d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().onCompatShadowChanged(); 3126d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 3136d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 3146d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 3156d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes /** 3166d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * Returns whether FloatingActionButton will add inner padding on platforms Lollipop and after. 3176d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 3186d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @return true if FloatingActionButton is adding inner padding on platforms Lollipop and after, 3196d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * to ensure consistent dimensions on all platforms. 3206d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 3216d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding 3226d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @see #setUseCompatPadding(boolean) 3236d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes */ 3246d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes public boolean getUseCompatPadding() { 3256d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes return mCompatPadding; 3266d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 3276d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 3280ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei @Nullable 3290ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei private InternalVisibilityChangedListener wrapOnVisibilityChangedListener( 3300ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei @Nullable final OnVisibilityChangedListener listener) { 3310ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei if (listener == null) { 3320ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei return null; 3330ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 3340ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 3350ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei return new InternalVisibilityChangedListener() { 3360ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei @Override 3370ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void onShown() { 3380ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei listener.onShown(FloatingActionButton.this); 3390ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 3400ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 3410ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei @Override 3420ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void onHidden() { 3430ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei listener.onHidden(FloatingActionButton.this); 3440ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 3450ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei }; 3469840efe3dbdc7026521da8576574c55120782f6cChris Banes } 3479840efe3dbdc7026521da8576574c55120782f6cChris Banes 3489840efe3dbdc7026521da8576574c55120782f6cChris Banes final int getSizeDimension() { 3499840efe3dbdc7026521da8576574c55120782f6cChris Banes switch (mSize) { 3509840efe3dbdc7026521da8576574c55120782f6cChris Banes case SIZE_MINI: 351a577676a64e5353b8ec927117151aa6be84adf66Chris Banes return getResources().getDimensionPixelSize(R.dimen.design_fab_size_mini); 3529840efe3dbdc7026521da8576574c55120782f6cChris Banes case SIZE_NORMAL: 3539840efe3dbdc7026521da8576574c55120782f6cChris Banes default: 354a577676a64e5353b8ec927117151aa6be84adf66Chris Banes return getResources().getDimensionPixelSize(R.dimen.design_fab_size_normal); 3559840efe3dbdc7026521da8576574c55120782f6cChris Banes } 3569840efe3dbdc7026521da8576574c55120782f6cChris Banes } 3579840efe3dbdc7026521da8576574c55120782f6cChris Banes 3589840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 359d9770e12c8ff2d4417700492c6616572be897e93Chris Banes protected void onAttachedToWindow() { 360d9770e12c8ff2d4417700492c6616572be897e93Chris Banes super.onAttachedToWindow(); 361d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().onAttachedToWindow(); 362d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 363d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 364d9770e12c8ff2d4417700492c6616572be897e93Chris Banes @Override 365d9770e12c8ff2d4417700492c6616572be897e93Chris Banes protected void onDetachedFromWindow() { 366d9770e12c8ff2d4417700492c6616572be897e93Chris Banes super.onDetachedFromWindow(); 367d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().onDetachedFromWindow(); 368d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 369d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 370d9770e12c8ff2d4417700492c6616572be897e93Chris Banes @Override 3719840efe3dbdc7026521da8576574c55120782f6cChris Banes protected void drawableStateChanged() { 3729840efe3dbdc7026521da8576574c55120782f6cChris Banes super.drawableStateChanged(); 373d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().onDrawableStateChanged(getDrawableState()); 3749840efe3dbdc7026521da8576574c55120782f6cChris Banes } 3759840efe3dbdc7026521da8576574c55120782f6cChris Banes 3769840efe3dbdc7026521da8576574c55120782f6cChris Banes @TargetApi(Build.VERSION_CODES.HONEYCOMB) 3779840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 3789840efe3dbdc7026521da8576574c55120782f6cChris Banes public void jumpDrawablesToCurrentState() { 3799840efe3dbdc7026521da8576574c55120782f6cChris Banes super.jumpDrawablesToCurrentState(); 380d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().jumpDrawableToCurrentState(); 3819840efe3dbdc7026521da8576574c55120782f6cChris Banes } 3829840efe3dbdc7026521da8576574c55120782f6cChris Banes 383d9cbe69a6661315238d856abc22578d03666f63bChris Banes /** 384d9cbe69a6661315238d856abc22578d03666f63bChris Banes * Return in {@code rect} the bounds of the actual floating action button content in view-local 385d9cbe69a6661315238d856abc22578d03666f63bChris Banes * coordinates. This is defined as anything within any visible shadow. 386d9cbe69a6661315238d856abc22578d03666f63bChris Banes * 387d9cbe69a6661315238d856abc22578d03666f63bChris Banes * @return true if this view actually has been laid out and has a content rect, else false. 388d9cbe69a6661315238d856abc22578d03666f63bChris Banes */ 389d9cbe69a6661315238d856abc22578d03666f63bChris Banes public boolean getContentRect(@NonNull Rect rect) { 390d9cbe69a6661315238d856abc22578d03666f63bChris Banes if (ViewCompat.isLaidOut(this)) { 391d9cbe69a6661315238d856abc22578d03666f63bChris Banes rect.set(0, 0, getWidth(), getHeight()); 392d9cbe69a6661315238d856abc22578d03666f63bChris Banes rect.left += mShadowPadding.left; 393d9cbe69a6661315238d856abc22578d03666f63bChris Banes rect.top += mShadowPadding.top; 394d9cbe69a6661315238d856abc22578d03666f63bChris Banes rect.right -= mShadowPadding.right; 395d9cbe69a6661315238d856abc22578d03666f63bChris Banes rect.bottom -= mShadowPadding.bottom; 396d9cbe69a6661315238d856abc22578d03666f63bChris Banes return true; 397d9cbe69a6661315238d856abc22578d03666f63bChris Banes } else { 398d9cbe69a6661315238d856abc22578d03666f63bChris Banes return false; 399d9cbe69a6661315238d856abc22578d03666f63bChris Banes } 400d9cbe69a6661315238d856abc22578d03666f63bChris Banes } 401d9cbe69a6661315238d856abc22578d03666f63bChris Banes 4023d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes /** 4033d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes * Returns the FloatingActionButton's background, minus any compatible shadow implementation. 4043d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes */ 4053d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes @NonNull 4063d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes public Drawable getContentBackground() { 407d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes return getImpl().getContentBackground(); 4083d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes } 4093d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 4109840efe3dbdc7026521da8576574c55120782f6cChris Banes private static int resolveAdjustedSize(int desiredSize, int measureSpec) { 4119840efe3dbdc7026521da8576574c55120782f6cChris Banes int result = desiredSize; 4129840efe3dbdc7026521da8576574c55120782f6cChris Banes int specMode = MeasureSpec.getMode(measureSpec); 4139840efe3dbdc7026521da8576574c55120782f6cChris Banes int specSize = MeasureSpec.getSize(measureSpec); 4149840efe3dbdc7026521da8576574c55120782f6cChris Banes switch (specMode) { 4159840efe3dbdc7026521da8576574c55120782f6cChris Banes case MeasureSpec.UNSPECIFIED: 4169840efe3dbdc7026521da8576574c55120782f6cChris Banes // Parent says we can be as big as we want. Just don't be larger 4179840efe3dbdc7026521da8576574c55120782f6cChris Banes // than max size imposed on ourselves. 4189840efe3dbdc7026521da8576574c55120782f6cChris Banes result = desiredSize; 4199840efe3dbdc7026521da8576574c55120782f6cChris Banes break; 4209840efe3dbdc7026521da8576574c55120782f6cChris Banes case MeasureSpec.AT_MOST: 4219840efe3dbdc7026521da8576574c55120782f6cChris Banes // Parent says we can be as big as we want, up to specSize. 4229840efe3dbdc7026521da8576574c55120782f6cChris Banes // Don't be larger than specSize, and don't be larger than 4239840efe3dbdc7026521da8576574c55120782f6cChris Banes // the max size imposed on ourselves. 4249840efe3dbdc7026521da8576574c55120782f6cChris Banes result = Math.min(desiredSize, specSize); 4259840efe3dbdc7026521da8576574c55120782f6cChris Banes break; 4269840efe3dbdc7026521da8576574c55120782f6cChris Banes case MeasureSpec.EXACTLY: 4279840efe3dbdc7026521da8576574c55120782f6cChris Banes // No choice. Do what we are told. 4289840efe3dbdc7026521da8576574c55120782f6cChris Banes result = specSize; 4299840efe3dbdc7026521da8576574c55120782f6cChris Banes break; 4309840efe3dbdc7026521da8576574c55120782f6cChris Banes } 4319840efe3dbdc7026521da8576574c55120782f6cChris Banes return result; 4329840efe3dbdc7026521da8576574c55120782f6cChris Banes } 4339840efe3dbdc7026521da8576574c55120782f6cChris Banes 4349840efe3dbdc7026521da8576574c55120782f6cChris Banes static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) { 4359840efe3dbdc7026521da8576574c55120782f6cChris Banes switch (value) { 4369840efe3dbdc7026521da8576574c55120782f6cChris Banes case 3: 4379840efe3dbdc7026521da8576574c55120782f6cChris Banes return PorterDuff.Mode.SRC_OVER; 4389840efe3dbdc7026521da8576574c55120782f6cChris Banes case 5: 4399840efe3dbdc7026521da8576574c55120782f6cChris Banes return PorterDuff.Mode.SRC_IN; 4409840efe3dbdc7026521da8576574c55120782f6cChris Banes case 9: 4419840efe3dbdc7026521da8576574c55120782f6cChris Banes return PorterDuff.Mode.SRC_ATOP; 4429840efe3dbdc7026521da8576574c55120782f6cChris Banes case 14: 4439840efe3dbdc7026521da8576574c55120782f6cChris Banes return PorterDuff.Mode.MULTIPLY; 4449840efe3dbdc7026521da8576574c55120782f6cChris Banes case 15: 4459840efe3dbdc7026521da8576574c55120782f6cChris Banes return PorterDuff.Mode.SCREEN; 4469840efe3dbdc7026521da8576574c55120782f6cChris Banes default: 4479840efe3dbdc7026521da8576574c55120782f6cChris Banes return defaultMode; 4489840efe3dbdc7026521da8576574c55120782f6cChris Banes } 4499840efe3dbdc7026521da8576574c55120782f6cChris Banes } 45014d064edb3e4a16a3b90a4a850560177bea1e60dChris Banes 45114d064edb3e4a16a3b90a4a850560177bea1e60dChris Banes /** 452b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Behavior designed for use with {@link FloatingActionButton} instances. It's main function 453b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * is to move {@link FloatingActionButton} views so that any displayed {@link Snackbar}s do 454b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * not cover them. 455b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 456b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static class Behavior extends CoordinatorLayout.Behavior<FloatingActionButton> { 457b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // We only support the FAB <> Snackbar shift movement on Honeycomb and above. This is 458b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // because we can use view translation properties which greatly simplifies the code. 459b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final boolean SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11; 460b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 461a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes private ValueAnimatorCompat mFabTranslationYAnimator; 46218d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes private float mFabTranslationY; 463a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private Rect mTmpRect; 464b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 465b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 466b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public boolean layoutDependsOn(CoordinatorLayout parent, 467be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes FloatingActionButton child, View dependency) { 468a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes // We're dependent on all SnackbarLayouts (if enabled) 469a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout; 470b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 471b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 472b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 473b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, 474a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes View dependency) { 475a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes if (dependency instanceof Snackbar.SnackbarLayout) { 476a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes updateFabTranslationForSnackbar(parent, child, dependency); 477a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } else if (dependency instanceof AppBarLayout) { 478be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // If we're depending on an AppBarLayout we will show/hide it automatically 479be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // if the FAB is anchored to the AppBarLayout 480be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes updateFabVisibility(parent, (AppBarLayout) dependency, child); 481be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 482be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes return false; 483be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 484a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 485be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes private boolean updateFabVisibility(CoordinatorLayout parent, 486be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes AppBarLayout appBarLayout, FloatingActionButton child) { 487be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes final CoordinatorLayout.LayoutParams lp = 488be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes (CoordinatorLayout.LayoutParams) child.getLayoutParams(); 489be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes if (lp.getAnchorId() != appBarLayout.getId()) { 490be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // The anchor ID doesn't match the dependency, so we won't automatically 491be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // show/hide the FAB 492be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes return false; 493be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 494a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 495fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes if (child.getUserSetVisibility() != VISIBLE) { 496fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes // The view isn't set to be visible so skip changing it's visibility 497fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes return false; 498fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes } 499fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes 500be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes if (mTmpRect == null) { 501be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes mTmpRect = new Rect(); 502a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 503be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 504be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // First, let's get the visible rect of the dependency 505be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes final Rect rect = mTmpRect; 506be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes ViewGroupUtils.getDescendantRect(parent, appBarLayout, rect); 507be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 508be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) { 509be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // If the anchor's bottom is below the seam, we'll animate our FAB out 510fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes child.hide(null, false); 511be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } else { 512be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // Else, we'll animate our FAB back in 513fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes child.show(null, false); 514be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 515be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes return true; 516b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 517b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 518a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private void updateFabTranslationForSnackbar(CoordinatorLayout parent, 519a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes final FloatingActionButton fab, View snackbar) { 52018d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes final float targetTransY = getFabTranslationYForSnackbar(parent, fab); 52118d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes if (mFabTranslationY == targetTransY) { 52218d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes // We're already at (or currently animating to) the target value, return... 52318d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes return; 52418d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes } 52518d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes 52618d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes final float currentTransY = ViewCompat.getTranslationY(fab); 52718d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes 528a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes // Make sure that any current animation is cancelled 529a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes if (mFabTranslationYAnimator != null && mFabTranslationYAnimator.isRunning()) { 530a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationYAnimator.cancel(); 531a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes } 532a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes 533e33473d0e35315c02243363a7479a2c361765751Chris Banes if (fab.isShown() 534e33473d0e35315c02243363a7479a2c361765751Chris Banes && Math.abs(currentTransY - targetTransY) > (fab.getHeight() * 0.667f)) { 53518d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes // If the FAB will be travelling by more than 2/3 of it's height, let's animate 53618d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes // it instead 537a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes if (mFabTranslationYAnimator == null) { 538a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationYAnimator = ViewUtils.createAnimator(); 539a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationYAnimator.setInterpolator( 540a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR); 541a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationYAnimator.setUpdateListener( 542a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes new ValueAnimatorCompat.AnimatorUpdateListener() { 543a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes @Override 544a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes public void onAnimationUpdate(ValueAnimatorCompat animator) { 545a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes ViewCompat.setTranslationY(fab, 546a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes animator.getAnimatedFloatValue()); 547a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes } 548a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes }); 549a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes } 550a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationYAnimator.setFloatValues(currentTransY, targetTransY); 551a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationYAnimator.start(); 55218d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes } else { 55318d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes // Now update the translation Y 55418d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes ViewCompat.setTranslationY(fab, targetTransY); 55518d22257ccfb5cebb3ccd2450736e735ed1fb9bbChris Banes } 556a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes 557a419ee1ef9aef8b567f1ccd8c29d01ec7bff4cc9Chris Banes mFabTranslationY = targetTransY; 558b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 559b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 560a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private float getFabTranslationYForSnackbar(CoordinatorLayout parent, 561a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes FloatingActionButton fab) { 562b7f9224b1495db47eb8fd813b5912250e900770aChris Banes float minOffset = 0; 563a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes final List<View> dependencies = parent.getDependencies(fab); 564a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes for (int i = 0, z = dependencies.size(); i < z; i++) { 565a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes final View view = dependencies.get(i); 566a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) { 567a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes minOffset = Math.min(minOffset, 568a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes ViewCompat.getTranslationY(view) - view.getHeight()); 569b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 570b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 571a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 572b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return minOffset; 573b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 574b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 575e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes @Override 576e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes public boolean onLayoutChild(CoordinatorLayout parent, FloatingActionButton child, 577e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes int layoutDirection) { 578be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // First, lets make sure that the visibility of the FAB is consistent 579be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes final List<View> dependencies = parent.getDependencies(child); 580be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes for (int i = 0, count = dependencies.size(); i < count; i++) { 581be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes final View dependency = dependencies.get(i); 582be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes if (dependency instanceof AppBarLayout 583be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes && updateFabVisibility(parent, (AppBarLayout) dependency, child)) { 584be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes break; 585be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 586be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes } 587be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes // Now let the CoordinatorLayout lay out the FAB 588e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes parent.onLayoutChild(child, layoutDirection); 589e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes // Now offset it if needed 590e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes offsetIfNeeded(parent, child); 591e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes return true; 592e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } 593e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes 594e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes /** 595e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes * Pre-Lollipop we use padding so that the shadow has enough space to be drawn. This method 596e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes * offsets our layout position so that we're positioned correctly if we're on one of 597e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes * our parent's edges. 598e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes */ 599e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes private void offsetIfNeeded(CoordinatorLayout parent, FloatingActionButton fab) { 600e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes final Rect padding = fab.mShadowPadding; 601e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes 602e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes if (padding != null && padding.centerX() > 0 && padding.centerY() > 0) { 603e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes final CoordinatorLayout.LayoutParams lp = 604e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); 605e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes 606e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes int offsetTB = 0, offsetLR = 0; 607e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes 608e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes if (fab.getRight() >= parent.getWidth() - lp.rightMargin) { 609e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes // If we're on the left edge, shift it the right 610e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes offsetLR = padding.right; 611e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } else if (fab.getLeft() <= lp.leftMargin) { 612e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes // If we're on the left edge, shift it the left 613e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes offsetLR = -padding.left; 614e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } 615e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes if (fab.getBottom() >= parent.getBottom() - lp.bottomMargin) { 616e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes // If we're on the bottom edge, shift it down 617e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes offsetTB = padding.bottom; 618e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } else if (fab.getTop() <= lp.topMargin) { 619e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes // If we're on the top edge, shift it up 620e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes offsetTB = -padding.top; 621e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } 622e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes 623e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes fab.offsetTopAndBottom(offsetTB); 624e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes fab.offsetLeftAndRight(offsetLR); 625e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } 626e882ef3492de3d2bb687b454e08b870b06d8f4e2Chris Banes } 627b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 6286d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 6296d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes /** 6306d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * Returns the backward compatible elevation of the FloatingActionButton. 6316d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 6322b1d1d93a93070601d3894f523d6421c64544246Chris Banes * @return the backward compatible elevation in pixels. 6336d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation 6341e220ff878c4b9c22aff3a6afc20aa89449c1833Chris Banes * @see #setCompatElevation(float) 6356d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes */ 6361e220ff878c4b9c22aff3a6afc20aa89449c1833Chris Banes public float getCompatElevation() { 637d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes return getImpl().getElevation(); 6386d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 6396d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 6406d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes /** 6416d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * Updates the backward compatible elevation of the FloatingActionButton. 6426d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * 6436d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @param elevation The backward compatible elevation in pixels. 6446d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation 6451e220ff878c4b9c22aff3a6afc20aa89449c1833Chris Banes * @see #getCompatElevation() 6466d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes * @see #setUseCompatPadding(boolean) 6476d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes */ 6481e220ff878c4b9c22aff3a6afc20aa89449c1833Chris Banes public void setCompatElevation(float elevation) { 649d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes getImpl().setElevation(elevation); 6506d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 651cdc736866534c604c4015c78371ade52bb6d52dfChris Banes 652d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes private FloatingActionButtonImpl getImpl() { 653d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes if (mImpl == null) { 654d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes mImpl = createImpl(); 655d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes } 656d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes return mImpl; 657d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes } 658d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes 659d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes private FloatingActionButtonImpl createImpl() { 660cdc736866534c604c4015c78371ade52bb6d52dfChris Banes final int sdk = Build.VERSION.SDK_INT; 661cdc736866534c604c4015c78371ade52bb6d52dfChris Banes if (sdk >= 21) { 662d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl()); 663cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } else if (sdk >= 14) { 664d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes return new FloatingActionButtonIcs(this, new ShadowDelegateImpl()); 665cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } else { 666d95e0bb0271ae59387dd9d2ca402ad6f39d789d2Chris Banes return new FloatingActionButtonEclairMr1(this, new ShadowDelegateImpl()); 667cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 668cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 669cdc736866534c604c4015c78371ade52bb6d52dfChris Banes 670cdc736866534c604c4015c78371ade52bb6d52dfChris Banes private class ShadowDelegateImpl implements ShadowViewDelegate { 671cdc736866534c604c4015c78371ade52bb6d52dfChris Banes @Override 672cdc736866534c604c4015c78371ade52bb6d52dfChris Banes public float getRadius() { 673cdc736866534c604c4015c78371ade52bb6d52dfChris Banes return getSizeDimension() / 2f; 674cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 675cdc736866534c604c4015c78371ade52bb6d52dfChris Banes 676cdc736866534c604c4015c78371ade52bb6d52dfChris Banes @Override 677cdc736866534c604c4015c78371ade52bb6d52dfChris Banes public void setShadowPadding(int left, int top, int right, int bottom) { 678cdc736866534c604c4015c78371ade52bb6d52dfChris Banes mShadowPadding.set(left, top, right, bottom); 679cdc736866534c604c4015c78371ade52bb6d52dfChris Banes setPadding(left + mImagePadding, top + mImagePadding, 680cdc736866534c604c4015c78371ade52bb6d52dfChris Banes right + mImagePadding, bottom + mImagePadding); 681cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 682cdc736866534c604c4015c78371ade52bb6d52dfChris Banes 683cdc736866534c604c4015c78371ade52bb6d52dfChris Banes @Override 684cdc736866534c604c4015c78371ade52bb6d52dfChris Banes public void setBackgroundDrawable(Drawable background) { 685cdc736866534c604c4015c78371ade52bb6d52dfChris Banes FloatingActionButton.super.setBackgroundDrawable(background); 686cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 687cdc736866534c604c4015c78371ade52bb6d52dfChris Banes 688cdc736866534c604c4015c78371ade52bb6d52dfChris Banes @Override 689cdc736866534c604c4015c78371ade52bb6d52dfChris Banes public boolean isCompatPaddingEnabled() { 690cdc736866534c604c4015c78371ade52bb6d52dfChris Banes return mCompatPadding; 691cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 692cdc736866534c604c4015c78371ade52bb6d52dfChris Banes } 6939840efe3dbdc7026521da8576574c55120782f6cChris Banes} 694