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.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.os.Build; 22import android.support.annotation.Nullable; 23import android.support.v4.view.ViewCompat; 24import android.view.View; 25 26class FloatingActionButtonIcs extends FloatingActionButtonGingerbread { 27 28 private float mRotation; 29 30 FloatingActionButtonIcs(VisibilityAwareImageButton view, 31 ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) { 32 super(view, shadowViewDelegate, animatorCreator); 33 mRotation = mView.getRotation(); 34 } 35 36 @Override 37 boolean requirePreDrawListener() { 38 return true; 39 } 40 41 @Override 42 void onPreDraw() { 43 final float rotation = mView.getRotation(); 44 if (mRotation != rotation) { 45 mRotation = rotation; 46 updateFromViewRotation(); 47 } 48 } 49 50 @Override 51 void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) { 52 if (isOrWillBeHidden()) { 53 // We either are or will soon be hidden, skip the call 54 return; 55 } 56 57 mView.animate().cancel(); 58 59 if (shouldAnimateVisibilityChange()) { 60 mAnimState = ANIM_STATE_HIDING; 61 62 mView.animate() 63 .scaleX(0f) 64 .scaleY(0f) 65 .alpha(0f) 66 .setDuration(SHOW_HIDE_ANIM_DURATION) 67 .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR) 68 .setListener(new AnimatorListenerAdapter() { 69 private boolean mCancelled; 70 71 @Override 72 public void onAnimationStart(Animator animation) { 73 mView.internalSetVisibility(View.VISIBLE, fromUser); 74 mCancelled = false; 75 } 76 77 @Override 78 public void onAnimationCancel(Animator animation) { 79 mCancelled = true; 80 } 81 82 @Override 83 public void onAnimationEnd(Animator animation) { 84 mAnimState = ANIM_STATE_NONE; 85 86 if (!mCancelled) { 87 mView.internalSetVisibility(View.GONE, fromUser); 88 if (listener != null) { 89 listener.onHidden(); 90 } 91 } 92 } 93 }); 94 } else { 95 // If the view isn't laid out, or we're in the editor, don't run the animation 96 mView.internalSetVisibility(View.GONE, fromUser); 97 if (listener != null) { 98 listener.onHidden(); 99 } 100 } 101 } 102 103 @Override 104 void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) { 105 if (isOrWillBeShown()) { 106 // We either are or will soon be visible, skip the call 107 return; 108 } 109 110 mView.animate().cancel(); 111 112 if (shouldAnimateVisibilityChange()) { 113 mAnimState = ANIM_STATE_SHOWING; 114 115 if (mView.getVisibility() != View.VISIBLE) { 116 // If the view isn't visible currently, we'll animate it from a single pixel 117 mView.setAlpha(0f); 118 mView.setScaleY(0f); 119 mView.setScaleX(0f); 120 } 121 122 mView.animate() 123 .scaleX(1f) 124 .scaleY(1f) 125 .alpha(1f) 126 .setDuration(SHOW_HIDE_ANIM_DURATION) 127 .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR) 128 .setListener(new AnimatorListenerAdapter() { 129 @Override 130 public void onAnimationStart(Animator animation) { 131 mView.internalSetVisibility(View.VISIBLE, fromUser); 132 } 133 134 @Override 135 public void onAnimationEnd(Animator animation) { 136 mAnimState = ANIM_STATE_NONE; 137 if (listener != null) { 138 listener.onShown(); 139 } 140 } 141 }); 142 } else { 143 mView.internalSetVisibility(View.VISIBLE, fromUser); 144 mView.setAlpha(1f); 145 mView.setScaleY(1f); 146 mView.setScaleX(1f); 147 if (listener != null) { 148 listener.onShown(); 149 } 150 } 151 } 152 153 private boolean shouldAnimateVisibilityChange() { 154 return ViewCompat.isLaidOut(mView) && !mView.isInEditMode(); 155 } 156 157 private void updateFromViewRotation() { 158 if (Build.VERSION.SDK_INT == 19) { 159 // KitKat seems to have an issue with views which are rotated with angles which are 160 // not divisible by 90. Worked around by moving to software rendering in these cases. 161 if ((mRotation % 90) != 0) { 162 if (mView.getLayerType() != View.LAYER_TYPE_SOFTWARE) { 163 mView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 164 } 165 } else { 166 if (mView.getLayerType() != View.LAYER_TYPE_NONE) { 167 mView.setLayerType(View.LAYER_TYPE_NONE, null); 168 } 169 } 170 } 171 172 // Offset any View rotation 173 if (mShadowDrawable != null) { 174 mShadowDrawable.setRotation(-mRotation); 175 } 176 if (mBorderDrawable != null) { 177 mBorderDrawable.setRotation(-mRotation); 178 } 179 } 180} 181