FloatingActionButtonLollipop.java revision 8f886fe8c7e23fe6ccb8734167c960c2ed3429c3
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 19f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banesimport android.animation.AnimatorSet; 209840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.animation.ObjectAnimator; 219840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.animation.StateListAnimator; 229840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.annotation.TargetApi; 239840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.content.res.ColorStateList; 249840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.PorterDuff; 256d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banesimport android.graphics.Rect; 269840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.drawable.Drawable; 276d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banesimport android.graphics.drawable.InsetDrawable; 28cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banesimport android.graphics.drawable.LayerDrawable; 299840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.drawable.RippleDrawable; 308f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.annotation.RequiresApi; 317e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 32f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banesimport android.view.View; 339840efe3dbdc7026521da8576574c55120782f6cChris Banes 348f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette@RequiresApi(21) 358f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette@TargetApi(21) 369ec922c215ed95a4bbd8bd7940e81dcfe6926893Chris Banesclass FloatingActionButtonLollipop extends FloatingActionButtonIcs { 379840efe3dbdc7026521da8576574c55120782f6cChris Banes 386d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes private InsetDrawable mInsetDrawable; 399840efe3dbdc7026521da8576574c55120782f6cChris Banes 40fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes FloatingActionButtonLollipop(VisibilityAwareImageButton view, 415a0083cc8328f05b15efe0293b7aa83723cdd9adChris Banes ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) { 425a0083cc8328f05b15efe0293b7aa83723cdd9adChris Banes super(view, shadowViewDelegate, animatorCreator); 439840efe3dbdc7026521da8576574c55120782f6cChris Banes } 449840efe3dbdc7026521da8576574c55120782f6cChris Banes 459840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 46097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes void setBackgroundDrawable(ColorStateList backgroundTint, 47cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) { 48097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes // Now we need to tint the shape background with the tint 49097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes mShapeDrawable = DrawableCompat.wrap(createShapeDrawable()); 507e82b99953680915596eaf0eb35927388e574ca8Chris Banes DrawableCompat.setTintList(mShapeDrawable, backgroundTint); 519840efe3dbdc7026521da8576574c55120782f6cChris Banes if (backgroundTintMode != null) { 527e82b99953680915596eaf0eb35927388e574ca8Chris Banes DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode); 539840efe3dbdc7026521da8576574c55120782f6cChris Banes } 549840efe3dbdc7026521da8576574c55120782f6cChris Banes 55cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes final Drawable rippleContent; 56cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes if (borderWidth > 0) { 5780de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes mBorderDrawable = createBorderDrawable(borderWidth, backgroundTint); 5880de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes rippleContent = new LayerDrawable(new Drawable[]{mBorderDrawable, mShapeDrawable}); 59cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes } else { 60cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes mBorderDrawable = null; 61cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes rippleContent = mShapeDrawable; 62cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes } 63cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes 649840efe3dbdc7026521da8576574c55120782f6cChris Banes mRippleDrawable = new RippleDrawable(ColorStateList.valueOf(rippleColor), 65cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes rippleContent, null); 669840efe3dbdc7026521da8576574c55120782f6cChris Banes 673d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes mContentBackground = mRippleDrawable; 683d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 699840efe3dbdc7026521da8576574c55120782f6cChris Banes mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable); 709840efe3dbdc7026521da8576574c55120782f6cChris Banes } 719840efe3dbdc7026521da8576574c55120782f6cChris Banes 729840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 739840efe3dbdc7026521da8576574c55120782f6cChris Banes void setRippleColor(int rippleColor) { 748603357c9433b9aef1805413a3bfc4a4f8decc50Chris Banes if (mRippleDrawable instanceof RippleDrawable) { 758603357c9433b9aef1805413a3bfc4a4f8decc50Chris Banes ((RippleDrawable) mRippleDrawable).setColor(ColorStateList.valueOf(rippleColor)); 768603357c9433b9aef1805413a3bfc4a4f8decc50Chris Banes } else { 778603357c9433b9aef1805413a3bfc4a4f8decc50Chris Banes super.setRippleColor(rippleColor); 788603357c9433b9aef1805413a3bfc4a4f8decc50Chris Banes } 799840efe3dbdc7026521da8576574c55120782f6cChris Banes } 809840efe3dbdc7026521da8576574c55120782f6cChris Banes 819840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 82f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes void onElevationsChanged(final float elevation, final float pressedTranslationZ) { 83f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes final StateListAnimator stateListAnimator = new StateListAnimator(); 84f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes 85f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes // Animate elevation and translationZ to our values when pressed 86f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes AnimatorSet set = new AnimatorSet(); 8767a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) 8867a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ) 8967a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .setDuration(PRESSED_ANIM_DURATION)); 90f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set.setInterpolator(ANIM_INTERPOLATOR); 91f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set); 92f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes 93f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes // Same deal for when we're focused 94f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set = new AnimatorSet(); 9567a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) 9667a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ) 9767a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .setDuration(PRESSED_ANIM_DURATION)); 98f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set.setInterpolator(ANIM_INTERPOLATOR); 99f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set); 100f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes 101f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes // Animate translationZ to 0 if not pressed 102f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set = new AnimatorSet(); 10367a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen // Use an AnimatorSet to set a start delay since there is a bug with ValueAnimator that 10467a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen // prevents it from being cancelled properly when used with a StateListAnimator. 10567a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen AnimatorSet anim = new AnimatorSet(); 10667a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen anim.play(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f) 10767a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .setDuration(PRESSED_ANIM_DURATION)) 10867a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .after(PRESSED_ANIM_DURATION); 10967a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) 11067a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .with(anim); 111f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set.setInterpolator(ANIM_INTERPOLATOR); 112f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes stateListAnimator.addState(ENABLED_STATE_SET, set); 113f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes 114f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes // Animate everything to 0 when disabled 115f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set = new AnimatorSet(); 11667a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen set.play(ObjectAnimator.ofFloat(mView, "elevation", 0f).setDuration(0)) 11767a57dc8cb582d1dc66a2a87fbe51b48ab87168dJustin Klaassen .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f).setDuration(0)); 118f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes set.setInterpolator(ANIM_INTERPOLATOR); 119f0aec033caa46d2cdddad020b8748d24f921ad5bChris Banes stateListAnimator.addState(EMPTY_STATE_SET, set); 1209840efe3dbdc7026521da8576574c55120782f6cChris Banes 1219840efe3dbdc7026521da8576574c55120782f6cChris Banes mView.setStateListAnimator(stateListAnimator); 1226d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1236d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes if (mShadowViewDelegate.isCompatPaddingEnabled()) { 1246d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes updatePadding(); 1256d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1266d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1276d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1286d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes @Override 1296d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes public float getElevation() { 1306d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes return mView.getElevation(); 1316d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1326d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1336d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes @Override 1346d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes void onCompatShadowChanged() { 1356d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes updatePadding(); 1366d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1376d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1386d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes @Override 1396d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes void onPaddingUpdated(Rect padding) { 1406d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes if (mShadowViewDelegate.isCompatPaddingEnabled()) { 1416d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes mInsetDrawable = new InsetDrawable(mRippleDrawable, 1426d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes padding.left, padding.top, padding.right, padding.bottom); 1436d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes mShadowViewDelegate.setBackgroundDrawable(mInsetDrawable); 1446d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } else { 1456d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable); 1466d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1479840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1489840efe3dbdc7026521da8576574c55120782f6cChris Banes 1499840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 1509840efe3dbdc7026521da8576574c55120782f6cChris Banes void onDrawableStateChanged(int[] state) { 1519840efe3dbdc7026521da8576574c55120782f6cChris Banes // no-op 1529840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1539840efe3dbdc7026521da8576574c55120782f6cChris Banes 1549840efe3dbdc7026521da8576574c55120782f6cChris Banes @Override 1559840efe3dbdc7026521da8576574c55120782f6cChris Banes void jumpDrawableToCurrentState() { 1569840efe3dbdc7026521da8576574c55120782f6cChris Banes // no-op 1579840efe3dbdc7026521da8576574c55120782f6cChris Banes } 1589840efe3dbdc7026521da8576574c55120782f6cChris Banes 159d9770e12c8ff2d4417700492c6616572be897e93Chris Banes @Override 160d9770e12c8ff2d4417700492c6616572be897e93Chris Banes boolean requirePreDrawListener() { 161d9770e12c8ff2d4417700492c6616572be897e93Chris Banes return false; 162d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 163d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 16480de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes @Override 16580de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes CircularBorderDrawable newCircularDrawable() { 16680de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes return new CircularBorderDrawableLollipop(); 16780de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes } 1686d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 16915375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 1706d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes void getPadding(Rect rect) { 1716d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes if (mShadowViewDelegate.isCompatPaddingEnabled()) { 1726d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes final float radius = mShadowViewDelegate.getRadius(); 1736d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes final float maxShadowSize = getElevation() + mPressedTranslationZ; 1746d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes final int hPadding = (int) Math.ceil( 1756d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes ShadowDrawableWrapper.calculateHorizontalPadding(maxShadowSize, radius, false)); 1766d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes final int vPadding = (int) Math.ceil( 1776d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes ShadowDrawableWrapper.calculateVerticalPadding(maxShadowSize, radius, false)); 1786d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes rect.set(hPadding, vPadding, hPadding, vPadding); 1796d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } else { 1806d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes rect.set(0, 0, 0, 0); 1816d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1826d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 183124d52000d70f3a0ef64b1c70b72238441cbf0edDeepanshu Gupta} 184