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.content.res.ColorStateList; 2080de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banesimport android.content.res.Resources; 21097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banesimport android.graphics.Color; 229840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.PorterDuff; 236d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banesimport android.graphics.Rect; 249840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.graphics.drawable.Drawable; 25097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banesimport android.graphics.drawable.GradientDrawable; 260ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Weiimport android.support.annotation.Nullable; 27cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banesimport android.support.design.R; 28d9770e12c8ff2d4417700492c6616572be897e93Chris Banesimport android.view.ViewTreeObserver; 299840efe3dbdc7026521da8576574c55120782f6cChris Banes 309840efe3dbdc7026521da8576574c55120782f6cChris Banesabstract class FloatingActionButtonImpl { 319840efe3dbdc7026521da8576574c55120782f6cChris Banes 323d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes Drawable mShapeDrawable; 333d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes Drawable mRippleDrawable; 343d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes CircularBorderDrawable mBorderDrawable; 353d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes Drawable mContentBackground; 363d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 373d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes float mElevation; 383d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes float mPressedTranslationZ; 393d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 400ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei interface InternalVisibilityChangedListener { 410ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void onShown(); 420ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei public void onHidden(); 430ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei } 440ad7ef59b28d8ffafd551d2756b5a8ec47c90682Mark Wei 45be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes static final int SHOW_HIDE_ANIM_DURATION = 200; 46be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 479840efe3dbdc7026521da8576574c55120782f6cChris Banes static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed, 489840efe3dbdc7026521da8576574c55120782f6cChris Banes android.R.attr.state_enabled}; 499840efe3dbdc7026521da8576574c55120782f6cChris Banes static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused, 509840efe3dbdc7026521da8576574c55120782f6cChris Banes android.R.attr.state_enabled}; 519840efe3dbdc7026521da8576574c55120782f6cChris Banes static final int[] EMPTY_STATE_SET = new int[0]; 529840efe3dbdc7026521da8576574c55120782f6cChris Banes 53fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes final VisibilityAwareImageButton mView; 549840efe3dbdc7026521da8576574c55120782f6cChris Banes final ShadowViewDelegate mShadowViewDelegate; 559840efe3dbdc7026521da8576574c55120782f6cChris Banes 566d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes private final Rect mTmpRect = new Rect(); 57d9770e12c8ff2d4417700492c6616572be897e93Chris Banes private ViewTreeObserver.OnPreDrawListener mPreDrawListener; 58d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 59fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes FloatingActionButtonImpl(VisibilityAwareImageButton view, 60fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes ShadowViewDelegate shadowViewDelegate) { 619840efe3dbdc7026521da8576574c55120782f6cChris Banes mView = view; 629840efe3dbdc7026521da8576574c55120782f6cChris Banes mShadowViewDelegate = shadowViewDelegate; 639840efe3dbdc7026521da8576574c55120782f6cChris Banes } 649840efe3dbdc7026521da8576574c55120782f6cChris Banes 65097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes abstract void setBackgroundDrawable(ColorStateList backgroundTint, 66cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth); 679840efe3dbdc7026521da8576574c55120782f6cChris Banes 689840efe3dbdc7026521da8576574c55120782f6cChris Banes abstract void setBackgroundTintList(ColorStateList tint); 699840efe3dbdc7026521da8576574c55120782f6cChris Banes 709840efe3dbdc7026521da8576574c55120782f6cChris Banes abstract void setBackgroundTintMode(PorterDuff.Mode tintMode); 719840efe3dbdc7026521da8576574c55120782f6cChris Banes 729840efe3dbdc7026521da8576574c55120782f6cChris Banes abstract void setRippleColor(int rippleColor); 739840efe3dbdc7026521da8576574c55120782f6cChris Banes 743d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes final void setElevation(float elevation) { 753d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes if (mElevation != elevation) { 763d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes mElevation = elevation; 773d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes onElevationChanged(elevation); 783d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes } 793d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes } 803d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 816d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes abstract float getElevation(); 826d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 833d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes final void setPressedTranslationZ(float translationZ) { 843d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes if (mPressedTranslationZ != translationZ) { 853d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes mPressedTranslationZ = translationZ; 863d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes onTranslationZChanged(translationZ); 873d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes } 883d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes } 893d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 903d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes abstract void onElevationChanged(float elevation); 919840efe3dbdc7026521da8576574c55120782f6cChris Banes 923d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes abstract void onTranslationZChanged(float translationZ); 939840efe3dbdc7026521da8576574c55120782f6cChris Banes 949840efe3dbdc7026521da8576574c55120782f6cChris Banes abstract void onDrawableStateChanged(int[] state); 959840efe3dbdc7026521da8576574c55120782f6cChris Banes 969840efe3dbdc7026521da8576574c55120782f6cChris Banes abstract void jumpDrawableToCurrentState(); 979840efe3dbdc7026521da8576574c55120782f6cChris Banes 98fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes abstract void hide(@Nullable InternalVisibilityChangedListener listener, boolean fromUser); 99be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 100fc780bab91bd4275ae2c3b75c3dfb327e008e4dbChris Banes abstract void show(@Nullable InternalVisibilityChangedListener listener, boolean fromUser); 101be48ed9161c09c4b2178ab6dbe28638222809fc7Chris Banes 1023d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes final Drawable getContentBackground() { 1033d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes return mContentBackground; 1043d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes } 1053d81c900316412b4130bf40e0dd8b0d3d3a93e78Chris Banes 1066d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes abstract void onCompatShadowChanged(); 1076d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1086d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes final void updatePadding() { 1096d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes Rect rect = mTmpRect; 1106d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes getPadding(rect); 1116d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes onPaddingUpdated(rect); 1126d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom); 1136d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes } 1146d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1156d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes abstract void getPadding(Rect rect); 1166d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 1176d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes void onPaddingUpdated(Rect padding) {} 1186d7a9a02765e4cb497081e66dafb5d9fa76f4312Chris Banes 119d9770e12c8ff2d4417700492c6616572be897e93Chris Banes void onAttachedToWindow() { 120d9770e12c8ff2d4417700492c6616572be897e93Chris Banes if (requirePreDrawListener()) { 121d9770e12c8ff2d4417700492c6616572be897e93Chris Banes ensurePreDrawListener(); 122d9770e12c8ff2d4417700492c6616572be897e93Chris Banes mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); 123d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 124d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 125d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 126d9770e12c8ff2d4417700492c6616572be897e93Chris Banes void onDetachedFromWindow() { 127d9770e12c8ff2d4417700492c6616572be897e93Chris Banes if (mPreDrawListener != null) { 128d9770e12c8ff2d4417700492c6616572be897e93Chris Banes mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener); 129d9770e12c8ff2d4417700492c6616572be897e93Chris Banes mPreDrawListener = null; 130d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 131d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 132d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 133d9770e12c8ff2d4417700492c6616572be897e93Chris Banes boolean requirePreDrawListener() { 134d9770e12c8ff2d4417700492c6616572be897e93Chris Banes return false; 135d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 136d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 137d9770e12c8ff2d4417700492c6616572be897e93Chris Banes CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) { 13880de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes final Resources resources = mView.getResources(); 13980de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes CircularBorderDrawable borderDrawable = newCircularDrawable(); 14080de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes borderDrawable.setGradientColors( 141a577676a64e5353b8ec927117151aa6be84adf66Chris Banes resources.getColor(R.color.design_fab_stroke_top_outer_color), 142a577676a64e5353b8ec927117151aa6be84adf66Chris Banes resources.getColor(R.color.design_fab_stroke_top_inner_color), 143a577676a64e5353b8ec927117151aa6be84adf66Chris Banes resources.getColor(R.color.design_fab_stroke_end_inner_color), 144a577676a64e5353b8ec927117151aa6be84adf66Chris Banes resources.getColor(R.color.design_fab_stroke_end_outer_color)); 14580de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes borderDrawable.setBorderWidth(borderWidth); 1468603357c9433b9aef1805413a3bfc4a4f8decc50Chris Banes borderDrawable.setBorderTint(backgroundTint); 147092f4b4fc5610ed1a2c4f5108066726ee59d8f16Chris Banes return borderDrawable; 14880de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes } 14980de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes 15080de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes CircularBorderDrawable newCircularDrawable() { 15180de0674c28a2bd9ade11f24a3b0e46ea83b6847Chris Banes return new CircularBorderDrawable(); 152cd78954a2b32d9c22686f12c194fac7e49566cf6Chris Banes } 153d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 154d9770e12c8ff2d4417700492c6616572be897e93Chris Banes void onPreDraw() { 155d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 156d9770e12c8ff2d4417700492c6616572be897e93Chris Banes 157d9770e12c8ff2d4417700492c6616572be897e93Chris Banes private void ensurePreDrawListener() { 158d9770e12c8ff2d4417700492c6616572be897e93Chris Banes if (mPreDrawListener == null) { 159d9770e12c8ff2d4417700492c6616572be897e93Chris Banes mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() { 160d9770e12c8ff2d4417700492c6616572be897e93Chris Banes @Override 161d9770e12c8ff2d4417700492c6616572be897e93Chris Banes public boolean onPreDraw() { 162d9770e12c8ff2d4417700492c6616572be897e93Chris Banes FloatingActionButtonImpl.this.onPreDraw(); 163d9770e12c8ff2d4417700492c6616572be897e93Chris Banes return true; 164d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 165d9770e12c8ff2d4417700492c6616572be897e93Chris Banes }; 166d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 167d9770e12c8ff2d4417700492c6616572be897e93Chris Banes } 168097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes 169097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes GradientDrawable createShapeDrawable() { 170097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes GradientDrawable d = new GradientDrawable(); 171097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes d.setShape(GradientDrawable.OVAL); 172097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes d.setColor(Color.WHITE); 173097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes return d; 174097e80a3c5518c6bf2e9f3f9b55ed9f4b5cc37e8Chris Banes } 1759840efe3dbdc7026521da8576574c55120782f6cChris Banes} 176