FloatingActionButtonImpl.java revision 15d1695da89eed196884b44fe90f19f83fb37a4f
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.design.widget; 18 19import android.content.res.ColorStateList; 20import android.content.res.Resources; 21import android.graphics.Color; 22import android.graphics.PorterDuff; 23import android.graphics.Rect; 24import android.graphics.drawable.Drawable; 25import android.graphics.drawable.GradientDrawable; 26import android.support.annotation.Nullable; 27import android.support.design.R; 28import android.view.View; 29import android.view.ViewTreeObserver; 30import android.view.animation.Interpolator; 31 32abstract class FloatingActionButtonImpl { 33 34 static final Interpolator ANIM_INTERPOLATOR = AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR; 35 static final long PRESSED_ANIM_DURATION = 100; 36 static final long PRESSED_ANIM_DELAY = 100; 37 38 static final int ANIM_STATE_NONE = 0; 39 static final int ANIM_STATE_HIDING = 1; 40 static final int ANIM_STATE_SHOWING = 2; 41 42 int mAnimState = ANIM_STATE_NONE; 43 44 Drawable mShapeDrawable; 45 Drawable mRippleDrawable; 46 CircularBorderDrawable mBorderDrawable; 47 Drawable mContentBackground; 48 49 float mElevation; 50 float mPressedTranslationZ; 51 52 interface InternalVisibilityChangedListener { 53 public void onShown(); 54 public void onHidden(); 55 } 56 57 static final int SHOW_HIDE_ANIM_DURATION = 200; 58 59 static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed, 60 android.R.attr.state_enabled}; 61 static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused, 62 android.R.attr.state_enabled}; 63 static final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled}; 64 static final int[] EMPTY_STATE_SET = new int[0]; 65 66 final VisibilityAwareImageButton mView; 67 final ShadowViewDelegate mShadowViewDelegate; 68 final ValueAnimatorCompat.Creator mAnimatorCreator; 69 70 private final Rect mTmpRect = new Rect(); 71 private ViewTreeObserver.OnPreDrawListener mPreDrawListener; 72 73 FloatingActionButtonImpl(VisibilityAwareImageButton view, 74 ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) { 75 mView = view; 76 mShadowViewDelegate = shadowViewDelegate; 77 mAnimatorCreator = animatorCreator; 78 } 79 80 abstract void setBackgroundDrawable(ColorStateList backgroundTint, 81 PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth); 82 83 abstract void setBackgroundTintList(ColorStateList tint); 84 85 abstract void setBackgroundTintMode(PorterDuff.Mode tintMode); 86 87 abstract void setRippleColor(int rippleColor); 88 89 final void setElevation(float elevation) { 90 if (mElevation != elevation) { 91 mElevation = elevation; 92 onElevationsChanged(elevation, mPressedTranslationZ); 93 } 94 } 95 96 abstract float getElevation(); 97 98 final void setPressedTranslationZ(float translationZ) { 99 if (mPressedTranslationZ != translationZ) { 100 mPressedTranslationZ = translationZ; 101 onElevationsChanged(mElevation, translationZ); 102 } 103 } 104 105 abstract void onElevationsChanged(float elevation, float pressedTranslationZ); 106 107 abstract void onDrawableStateChanged(int[] state); 108 109 abstract void jumpDrawableToCurrentState(); 110 111 abstract void hide(@Nullable InternalVisibilityChangedListener listener, boolean fromUser); 112 113 abstract void show(@Nullable InternalVisibilityChangedListener listener, boolean fromUser); 114 115 final Drawable getContentBackground() { 116 return mContentBackground; 117 } 118 119 abstract void onCompatShadowChanged(); 120 121 final void updatePadding() { 122 Rect rect = mTmpRect; 123 getPadding(rect); 124 onPaddingUpdated(rect); 125 mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom); 126 } 127 128 abstract void getPadding(Rect rect); 129 130 void onPaddingUpdated(Rect padding) {} 131 132 void onAttachedToWindow() { 133 if (requirePreDrawListener()) { 134 ensurePreDrawListener(); 135 mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); 136 } 137 } 138 139 void onDetachedFromWindow() { 140 if (mPreDrawListener != null) { 141 mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener); 142 mPreDrawListener = null; 143 } 144 } 145 146 boolean requirePreDrawListener() { 147 return false; 148 } 149 150 CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) { 151 final Resources resources = mView.getResources(); 152 CircularBorderDrawable borderDrawable = newCircularDrawable(); 153 borderDrawable.setGradientColors( 154 resources.getColor(R.color.design_fab_stroke_top_outer_color), 155 resources.getColor(R.color.design_fab_stroke_top_inner_color), 156 resources.getColor(R.color.design_fab_stroke_end_inner_color), 157 resources.getColor(R.color.design_fab_stroke_end_outer_color)); 158 borderDrawable.setBorderWidth(borderWidth); 159 borderDrawable.setBorderTint(backgroundTint); 160 return borderDrawable; 161 } 162 163 CircularBorderDrawable newCircularDrawable() { 164 return new CircularBorderDrawable(); 165 } 166 167 void onPreDraw() { 168 } 169 170 private void ensurePreDrawListener() { 171 if (mPreDrawListener == null) { 172 mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() { 173 @Override 174 public boolean onPreDraw() { 175 FloatingActionButtonImpl.this.onPreDraw(); 176 return true; 177 } 178 }; 179 } 180 } 181 182 GradientDrawable createShapeDrawable() { 183 GradientDrawable d = new GradientDrawable(); 184 d.setShape(GradientDrawable.OVAL); 185 d.setColor(Color.WHITE); 186 return d; 187 } 188 189 boolean isOrWillBeShown() { 190 if (mView.getVisibility() != View.VISIBLE) { 191 // If we not currently visible, return true if we're animating to be shown 192 return mAnimState == ANIM_STATE_SHOWING; 193 } else { 194 // Otherwise if we're visible, return true if we're not animating to be hidden 195 return mAnimState != ANIM_STATE_HIDING; 196 } 197 } 198 199 boolean isOrWillBeHidden() { 200 if (mView.getVisibility() == View.VISIBLE) { 201 // If we currently visible, return true if we're animating to be hidden 202 return mAnimState == ANIM_STATE_HIDING; 203 } else { 204 // Otherwise if we're not visible, return true if we're not animating to be shown 205 return mAnimState != ANIM_STATE_SHOWING; 206 } 207 } 208} 209