1 /* 2 * Copyright (C) 2013 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 17 package com.example.android.toongame; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.AnimatorSet; 22 import android.animation.ObjectAnimator; 23 import android.animation.PropertyValuesHolder; 24 import android.animation.TimeInterpolator; 25 import android.animation.ValueAnimator; 26 import android.app.Activity; 27 import android.content.res.ColorStateList; 28 import android.graphics.Color; 29 import android.graphics.Typeface; 30 import android.graphics.drawable.ShapeDrawable; 31 import android.graphics.drawable.shapes.OvalShape; 32 import android.os.Bundle; 33 import android.util.TypedValue; 34 import android.view.MotionEvent; 35 import android.view.View; 36 import android.view.ViewGroup; 37 import android.view.ViewTreeObserver; 38 import android.view.animation.AccelerateInterpolator; 39 import android.view.animation.DecelerateInterpolator; 40 import android.view.animation.LinearInterpolator; 41 import android.view.animation.OvershootInterpolator; 42 import android.widget.Button; 43 import android.widget.EditText; 44 import android.widget.RelativeLayout; 45 46 /** 47 * This activity, launched from the ToonGame activity, takes the user between three 48 * different setup screens where they choose a name, choose a difficulty rating, and 49 * enter important financial information. All of the screens are meant to be 50 * simple, engaging, and fun. 51 */ 52 public class PlayerSetupActivity extends Activity { 53 54 private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator(); 55 private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator(); 56 ViewGroup mContainer; 57 EditText mEditText; 58 59 private static final int NAME_STATE = 0; 60 private static final int DIFFICULTY_STATE = 1; 61 private static final int CREDIT_STATE = 2; 62 private int mEntryState = NAME_STATE; 63 64 SkewableTextView mNameTV, mDifficultyTV, mCreditTV; 65 66 ViewGroup mNameButtons, mDifficultyButtons, mCreditButtons1, mCreditButtons2; 67 68 Button mBobButton, mJaneButton, mPatButton; 69 70 private static final TimeInterpolator sOvershooter = new OvershootInterpolator(); 71 private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator(); 72 73 @Override onCreate(Bundle savedInstanceState)74 protected void onCreate(Bundle savedInstanceState) { 75 super.onCreate(savedInstanceState); 76 setContentView(R.layout.player_setup_layout); 77 overridePendingTransition(0, 0); 78 79 mContainer = (ViewGroup) findViewById(R.id.container); 80 mContainer.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); 81 82 mNameTV = (SkewableTextView) findViewById(R.id.nameTV); 83 mDifficultyTV = (SkewableTextView) findViewById(R.id.ageTV); 84 mCreditTV = (SkewableTextView) findViewById(R.id.creditTV); 85 86 mBobButton = setupButton(R.id.bobButton); 87 setupButton(R.id.janeButton); 88 setupButton(R.id.patButton); 89 setupButton(R.id.easyButton); 90 setupButton(R.id.hardButton); 91 setupButton(R.id.megaHardButton); 92 93 mNameButtons = (ViewGroup) findViewById(R.id.nameButtons); 94 mDifficultyButtons = (ViewGroup) findViewById(R.id.difficultyButtons); 95 mCreditButtons1 = (ViewGroup) findViewById(R.id.creditButtons1); 96 mCreditButtons2 = (ViewGroup) findViewById(R.id.creditButtons2); 97 } 98 99 @Override finish()100 public void finish() { 101 super.finish(); 102 overridePendingTransition(0, 0); 103 } 104 setupButton(int resourceId)105 private Button setupButton(int resourceId) { 106 Button button = (Button) findViewById(resourceId); 107 button.setOnTouchListener(mButtonPressListener); 108 return button; 109 } 110 111 private View.OnTouchListener mButtonPressListener = 112 new View.OnTouchListener() { 113 public boolean onTouch(View v, MotionEvent event) { 114 switch (event.getAction()) { 115 case MotionEvent.ACTION_DOWN: 116 v.animate().setDuration(ToonGame.SHORT_DURATION). 117 scaleX(.8f).scaleY(.8f).setInterpolator(sDecelerator); 118 break; 119 case MotionEvent.ACTION_UP: 120 v.animate().setDuration(ToonGame.SHORT_DURATION). 121 scaleX(1).scaleY(1).setInterpolator(sAccelerator); 122 break; 123 default: 124 break; 125 } 126 return false; 127 } 128 }; 129 buttonClick(View clickedView, int alignmentRule)130 public void buttonClick(View clickedView, int alignmentRule) { 131 ViewGroup parent = (ViewGroup) clickedView.getParent(); 132 for (int i = 0; i < parent.getChildCount(); ++i) { 133 Button child = (Button) parent.getChildAt(i); 134 if (child != clickedView) { 135 child.animate().alpha(0); 136 } else { 137 final Button buttonCopy = new Button(this); 138 child.setVisibility(View.INVISIBLE); 139 buttonCopy.setBackground(child.getBackground()); 140 buttonCopy.setText(((Button) child).getText()); 141 RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( 142 RelativeLayout.LayoutParams.WRAP_CONTENT, 143 RelativeLayout.LayoutParams.WRAP_CONTENT); 144 params.addRule(RelativeLayout.ALIGN_PARENT_TOP); 145 params.addRule(alignmentRule); 146 params.setMargins(25, 50, 25, 50); 147 buttonCopy.setLayoutParams(params); 148 buttonCopy.setPadding(child.getPaddingLeft(), child.getPaddingTop(), 149 child.getPaddingRight(), child.getPaddingBottom()); 150 buttonCopy.setTextSize(TypedValue.COMPLEX_UNIT_PX, child.getTextSize()); 151 buttonCopy.setTypeface(child.getTypeface(), Typeface.BOLD); 152 ColorStateList colors = child.getTextColors(); 153 buttonCopy.setTextColor(colors.getDefaultColor()); 154 final int[] oldLocationInWindow = new int[2]; 155 child.getLocationInWindow(oldLocationInWindow); 156 mContainer.addView(buttonCopy); 157 buttonCopy.getViewTreeObserver().addOnPreDrawListener( 158 new ViewTreeObserver.OnPreDrawListener() { 159 160 @Override 161 public boolean onPreDraw() { 162 buttonCopy.getViewTreeObserver().removeOnPreDrawListener(this); 163 int[] locationInWindow = new int[2]; 164 buttonCopy.getLocationInWindow(locationInWindow); 165 float deltaX = oldLocationInWindow[0] - locationInWindow[0]; 166 float deltaY = oldLocationInWindow[1] - locationInWindow[1]; 167 168 buttonCopy.setTranslationX(deltaX); 169 buttonCopy.setTranslationY(deltaY); 170 171 PropertyValuesHolder pvhSX = 172 PropertyValuesHolder.ofFloat(View.SCALE_X, 3); 173 PropertyValuesHolder pvhSY = 174 PropertyValuesHolder.ofFloat(View.SCALE_Y, 3); 175 ObjectAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder( 176 buttonCopy, pvhSX, pvhSY); 177 bounceAnim.setRepeatCount(1); 178 bounceAnim.setRepeatMode(ValueAnimator.REVERSE); 179 bounceAnim.setInterpolator(sDecelerator); 180 bounceAnim.setDuration(300); 181 182 PropertyValuesHolder pvhTX = 183 PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 0); 184 PropertyValuesHolder pvhTY = 185 PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0); 186 ObjectAnimator moveAnim = ObjectAnimator.ofPropertyValuesHolder( 187 buttonCopy, pvhTX, pvhTY); 188 moveAnim.setDuration(600); 189 bounceAnim.start(); 190 moveAnim.start(); 191 moveAnim.addListener(new AnimatorListenerAdapter() { 192 public void onAnimationEnd(Animator animation) { 193 switch (mEntryState) { 194 case (NAME_STATE) : 195 { 196 Runnable runnable = new Runnable() { 197 public void run() { 198 mDifficultyButtons.setVisibility(View.VISIBLE); 199 mNameButtons.setVisibility(View.GONE); 200 popChildrenIn(mDifficultyButtons, null); 201 } 202 }; 203 slideToNext(mNameTV, mDifficultyTV, runnable); 204 mEntryState = DIFFICULTY_STATE; 205 break; 206 } 207 case (DIFFICULTY_STATE) : 208 { 209 mDifficultyButtons.setVisibility(View.GONE); 210 for (int i = 0; i < 5; ++i) { 211 mCreditButtons1.addView(setupNumberButton(i)); 212 } 213 for (int i = 5; i < 10; ++i) { 214 mCreditButtons2.addView(setupNumberButton(i)); 215 } 216 Runnable runnable = new Runnable() { 217 public void run() { 218 mCreditButtons1.setVisibility(View.VISIBLE); 219 Runnable runnable = new Runnable() { 220 public void run() { 221 mCreditButtons2.setVisibility(View.VISIBLE); 222 popChildrenIn(mCreditButtons2, null); 223 } 224 }; 225 popChildrenIn(mCreditButtons1, runnable); 226 } 227 }; 228 slideToNext(mDifficultyTV, mCreditTV, runnable); 229 mEntryState = CREDIT_STATE; 230 } 231 break; 232 } 233 } 234 }); 235 return true; 236 } 237 }); 238 } 239 } 240 } 241 selectDifficulty(View clickedView)242 public void selectDifficulty(View clickedView) { 243 buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_RIGHT); 244 } 245 selectName(View clickedView)246 public void selectName(View clickedView) { 247 buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_LEFT); 248 } 249 setupNumberButton(int number)250 private Button setupNumberButton(int number) { 251 Button button = new Button(PlayerSetupActivity.this); 252 button.setTextSize(15); 253 button.setTextColor(Color.WHITE); 254 button.setTypeface(mBobButton.getTypeface(), Typeface.BOLD); 255 button.setText(Integer.toString(number)); 256 button.setPadding(0, 0, 0, 0); 257 258 OvalShape oval = new OvalShape(); 259 ShapeDrawable drawable = new ShapeDrawable(oval); 260 drawable.getPaint().setColor(0xFF << 24 | (int) (50 + 150 * Math.random()) << 16 | 261 (int) (50 + 150 * Math.random()) << 8 | (int) (50 + 150 * Math.random())); 262 button.setBackground(drawable); 263 264 button.setOnTouchListener(mButtonPressListener); 265 266 return button; 267 } 268 269 ViewTreeObserver.OnPreDrawListener mPreDrawListener = 270 new ViewTreeObserver.OnPreDrawListener() { 271 272 @Override 273 public boolean onPreDraw() { 274 mContainer.getViewTreeObserver().removeOnPreDrawListener(this); 275 mContainer.setScaleX(0); 276 mContainer.setScaleY(0); 277 mContainer.animate().scaleX(1).scaleY(1).setInterpolator(new OvershootInterpolator()); 278 mContainer.animate().setDuration(ToonGame.LONG_DURATION).withEndAction(new Runnable() { 279 280 @Override 281 public void run() { 282 ViewGroup buttonsParent = (ViewGroup) findViewById(R.id.nameButtons); 283 buttonsParent.setVisibility(View.VISIBLE); 284 popChildrenIn(buttonsParent, null); 285 } 286 }); 287 return false; 288 } 289 }; 290 popChildrenIn(ViewGroup parent, final Runnable endAction)291 private void popChildrenIn(ViewGroup parent, final Runnable endAction) { 292 // for all children, scale in one at a time 293 TimeInterpolator overshooter = new OvershootInterpolator(); 294 int childCount = parent.getChildCount(); 295 ObjectAnimator[] childAnims = new ObjectAnimator[childCount]; 296 for (int i = 0; i < childCount; ++i) { 297 View child = parent.getChildAt(i); 298 child.setScaleX(0); 299 child.setScaleY(0); 300 PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1); 301 PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1); 302 ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(child, pvhSX, pvhSY); 303 anim.setDuration(150); 304 anim.setInterpolator(overshooter); 305 childAnims[i] = anim; 306 } 307 AnimatorSet set = new AnimatorSet(); 308 set.playSequentially(childAnims); 309 set.start(); 310 if (endAction != null) { 311 set.addListener(new AnimatorListenerAdapter() { 312 public void onAnimationEnd(Animator animation) { 313 endAction.run(); 314 } 315 }); 316 } 317 } 318 slideToNext(final SkewableTextView currentView, final SkewableTextView nextView, final Runnable endAction)319 private void slideToNext(final SkewableTextView currentView, 320 final SkewableTextView nextView, final Runnable endAction) { 321 // skew/anticipate current view, slide off, set GONE, restore translation 322 ObjectAnimator currentSkewer = ObjectAnimator.ofFloat(currentView, "skewX", -.5f); 323 currentSkewer.setInterpolator(sDecelerator); 324 ObjectAnimator currentMover = ObjectAnimator.ofFloat(currentView, View.TRANSLATION_X, 325 -mContainer.getWidth()); 326 currentMover.setInterpolator(sLinearInterpolator); 327 currentMover.setDuration(ToonGame.MEDIUM_DURATION); 328 329 // set next view visible, translate off to right, skew, 330 // slide on in parallel, overshoot/wobble, unskew 331 nextView.setVisibility(View.VISIBLE); 332 nextView.setSkewX(-.5f); 333 nextView.setTranslationX(mContainer.getWidth()); 334 335 ObjectAnimator nextMover = ObjectAnimator.ofFloat(nextView, View.TRANSLATION_X, 0); 336 nextMover.setInterpolator(sAccelerator); 337 nextMover.setDuration(ToonGame.MEDIUM_DURATION); 338 ObjectAnimator nextSkewer = ObjectAnimator.ofFloat(nextView, "skewX", 0); 339 nextSkewer.setInterpolator(sOvershooter); 340 341 AnimatorSet moverSet = new AnimatorSet(); 342 moverSet.playTogether(currentMover, nextMover); 343 AnimatorSet fullSet = new AnimatorSet(); 344 fullSet.playSequentially(currentSkewer, moverSet, nextSkewer); 345 fullSet.addListener(new AnimatorListenerAdapter() { 346 @Override 347 public void onAnimationEnd(Animator animation) { 348 currentView.setSkewX(0); 349 currentView.setVisibility(View.GONE); 350 currentView.setTranslationX(0); 351 if (endAction != null) { 352 endAction.run(); 353 } 354 } 355 }); 356 357 fullSet.start(); 358 } 359 360 } 361