ModeOptions.java revision 591eec6465d29bbc053e164071c4c3a7c260a1d3
1/* 2 * Copyright (C) 2014 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 */ 16package com.android.camera.widget; 17 18import android.animation.Animator; 19import android.animation.AnimatorListenerAdapter; 20import android.animation.AnimatorSet; 21import android.animation.ObjectAnimator; 22import android.animation.ValueAnimator; 23import android.content.Context; 24import android.content.res.Configuration; 25import android.graphics.Canvas; 26import android.graphics.Path; 27import android.graphics.Paint; 28import android.graphics.RectF; 29import android.view.Gravity; 30import android.view.View; 31import android.widget.FrameLayout; 32import android.widget.LinearLayout; 33import android.util.AttributeSet; 34 35import com.android.camera.util.Gusterpolator; 36import com.android.camera2.R; 37 38public class ModeOptions extends FrameLayout { 39 private int mBackgroundColor; 40 private final Paint mPaint = new Paint(); 41 private final Path mPath = new Path(); 42 private boolean mIsHiddenOrHiding; 43 private RectF mAnimateFrom = new RectF(); 44 private View mViewToShowHide; 45 private View mModeOptionsButtons; 46 47 private AnimatorSet mVisibleAnimator; 48 private AnimatorSet mHiddenAnimator; 49 private boolean mDrawCircle; 50 private boolean mFill; 51 private static final int RADIUS_ANIMATION_TIME = 250; 52 private static final int SHOW_ALPHA_ANIMATION_TIME = 350; 53 private static final int HIDE_ALPHA_ANIMATION_TIME = 200; 54 private static final int PADDING_ANIMATION_TIME = 90; 55 56 private int mParentSize; 57 private boolean mIsPortrait; 58 59 public ModeOptions(Context context, AttributeSet attrs) { 60 super(context, attrs); 61 } 62 63 public void setViewToShowHide(View v) { 64 mViewToShowHide = v; 65 } 66 67 @Override 68 public void onFinishInflate() { 69 mIsHiddenOrHiding = true; 70 mBackgroundColor = getResources().getColor(R.color.mode_options_background); 71 mPaint.setAntiAlias(true); 72 mPaint.setColor(mBackgroundColor); 73 mModeOptionsButtons = findViewById(R.id.mode_options_buttons); 74 } 75 76 @Override 77 public void onConfigurationChanged(Configuration config) { 78 super.onConfigurationChanged(config); 79 80 FrameLayout.LayoutParams params = 81 (FrameLayout.LayoutParams) mModeOptionsButtons.getLayoutParams(); 82 83 if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { 84 params.gravity = Gravity.RIGHT; 85 } else { 86 params.gravity = Gravity.TOP; 87 } 88 89 mVisibleAnimator.end(); 90 mHiddenAnimator.end(); 91 92 mModeOptionsButtons.setLayoutParams(params); 93 } 94 95 96 @Override 97 public void onLayout(boolean changed, int left, int top, int right, int bottom) { 98 if (changed) { 99 mIsPortrait = (getResources().getConfiguration().orientation == 100 Configuration.ORIENTATION_PORTRAIT); 101 102 int buttonSize = getResources() 103 .getDimensionPixelSize(R.dimen.option_button_circle_size); 104 int buttonPadding = getResources() 105 .getDimensionPixelSize(R.dimen.mode_options_toggle_padding); 106 107 float rLeft, rRight, rTop, rBottom; 108 View parent = (View) getParent(); 109 if (mIsPortrait) { 110 rLeft = getWidth() - buttonPadding - buttonSize; 111 rTop = (getHeight() - buttonSize) / 2.0f; 112 113 mParentSize = parent.getWidth(); 114 } else { 115 rLeft = buttonPadding; 116 rTop = buttonPadding; 117 118 mParentSize = parent.getHeight(); 119 } 120 rRight = rLeft + buttonSize; 121 rBottom = rTop + buttonSize; 122 mAnimateFrom.set(rLeft, rTop, rRight, rBottom); 123 124 setupAnimators(); 125 } 126 127 super.onLayout(changed, left, top, right, bottom); 128 } 129 130 @Override 131 public void onDraw(Canvas canvas) { 132 if (mDrawCircle) { 133 canvas.drawPath(mPath, mPaint); 134 } else if (mFill) { 135 canvas.drawPaint(mPaint); 136 } 137 super.onDraw(canvas); 138 } 139 140 private void setupAnimators() { 141 final float fullSize = (mIsPortrait ? (float) getWidth() : (float) getHeight()); 142 143 // show 144 { 145 final ValueAnimator radiusAnimator = 146 ValueAnimator.ofFloat(mAnimateFrom.width()/2.0f, 147 fullSize-mAnimateFrom.width()/2.0f); 148 radiusAnimator.setDuration(RADIUS_ANIMATION_TIME); 149 radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 150 @Override 151 public void onAnimationUpdate(ValueAnimator animation) { 152 mPath.reset(); 153 mPath.addCircle(mAnimateFrom.centerX(), 154 mAnimateFrom.centerY(), 155 (Float) animation.getAnimatedValue(), 156 Path.Direction.CW); 157 mDrawCircle = true; 158 mFill = false; 159 invalidate(); 160 } 161 }); 162 radiusAnimator.addListener(new AnimatorListenerAdapter() { 163 @Override 164 public void onAnimationEnd(Animator animation) { 165 mPath.reset(); 166 mDrawCircle = false; 167 mFill = true; 168 invalidate(); 169 } 170 }); 171 172 final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 1.0f); 173 alphaAnimator.setDuration(SHOW_ALPHA_ANIMATION_TIME); 174 alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 175 @Override 176 public void onAnimationUpdate(ValueAnimator animation) { 177 mModeOptionsButtons.setAlpha((Float) animation.getAnimatedValue()); 178 invalidate(); 179 } 180 }); 181 alphaAnimator.addListener(new AnimatorListenerAdapter() { 182 @Override 183 public void onAnimationEnd(Animator animation) { 184 mModeOptionsButtons.setAlpha(1.0f); 185 invalidate(); 186 } 187 }); 188 189 final ValueAnimator paddingAnimator = ValueAnimator.ofInt(mParentSize, 0); 190 paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 191 @Override 192 public void onAnimationUpdate(ValueAnimator animation) { 193 if (mIsPortrait) { 194 mModeOptionsButtons 195 .setPadding((Integer) animation.getAnimatedValue(), 0, 0, 0); 196 } else { 197 mModeOptionsButtons 198 .setPadding(0, 0, 0, (Integer) animation.getAnimatedValue()); 199 } 200 requestLayout(); 201 invalidate(); 202 } 203 }); 204 paddingAnimator.setDuration(PADDING_ANIMATION_TIME); 205 paddingAnimator.addListener(new AnimatorListenerAdapter() { 206 @Override 207 public void onAnimationEnd(Animator animation) { 208 mModeOptionsButtons 209 .setPadding(0, 0, 0, 0); 210 211 requestLayout(); 212 invalidate(); 213 } 214 }); 215 216 mVisibleAnimator = new AnimatorSet(); 217 mVisibleAnimator.setInterpolator(Gusterpolator.INSTANCE); 218 mVisibleAnimator.playTogether(radiusAnimator, alphaAnimator, paddingAnimator); 219 } 220 221 // hide 222 { 223 final ValueAnimator radiusAnimator = 224 ValueAnimator.ofFloat(fullSize-mAnimateFrom.width()/2.0f, 225 mAnimateFrom.width()/2.0f); 226 radiusAnimator.setDuration(RADIUS_ANIMATION_TIME); 227 radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 228 @Override 229 public void onAnimationUpdate(ValueAnimator animation) { 230 mPath.reset(); 231 mPath.addCircle(mAnimateFrom.centerX(), 232 mAnimateFrom.centerY(), 233 (Float) animation.getAnimatedValue(), 234 Path.Direction.CW); 235 mDrawCircle = true; 236 mFill = false; 237 invalidate(); 238 } 239 }); 240 radiusAnimator.addListener(new AnimatorListenerAdapter() { 241 @Override 242 public void onAnimationEnd(Animator animation) { 243 if (mViewToShowHide != null) { 244 mPath.reset(); 245 mViewToShowHide.setVisibility(View.VISIBLE); 246 mDrawCircle = false; 247 mFill = false; 248 invalidate(); 249 } 250 } 251 }); 252 253 final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f); 254 alphaAnimator.setDuration(HIDE_ALPHA_ANIMATION_TIME); 255 alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 256 @Override 257 public void onAnimationUpdate(ValueAnimator animation) { 258 mModeOptionsButtons.setAlpha((Float) animation.getAnimatedValue()); 259 invalidate(); 260 } 261 }); 262 alphaAnimator.addListener(new AnimatorListenerAdapter() { 263 @Override 264 public void onAnimationEnd(Animator animation) { 265 mModeOptionsButtons.setAlpha(0.0f); 266 mModeOptionsButtons.setVisibility(View.INVISIBLE); 267 invalidate(); 268 } 269 }); 270 271 mHiddenAnimator = new AnimatorSet(); 272 mHiddenAnimator.setInterpolator(Gusterpolator.INSTANCE); 273 mHiddenAnimator.playTogether(radiusAnimator, alphaAnimator); 274 } 275 } 276 277 public void animateVisible() { 278 if (mIsHiddenOrHiding) { 279 if (mViewToShowHide != null) { 280 mViewToShowHide.setVisibility(View.INVISIBLE); 281 } 282 mHiddenAnimator.cancel(); 283 mVisibleAnimator.end(); 284 mModeOptionsButtons.setVisibility(View.VISIBLE); 285 mVisibleAnimator.start(); 286 } 287 mIsHiddenOrHiding = false; 288 } 289 290 public void animateHidden() { 291 if (!mIsHiddenOrHiding) { 292 mVisibleAnimator.cancel(); 293 mHiddenAnimator.end(); 294 mHiddenAnimator.start(); 295 } 296 mIsHiddenOrHiding = true; 297 } 298}