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.squashandstretch; 18 19 import android.animation.AnimatorSet; 20 import android.animation.ObjectAnimator; 21 import android.animation.PropertyValuesHolder; 22 import android.animation.ValueAnimator; 23 import android.app.Activity; 24 import android.os.Bundle; 25 import android.view.Menu; 26 import android.view.MenuItem; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.view.animation.AccelerateInterpolator; 30 import android.view.animation.DecelerateInterpolator; 31 32 /** 33 * This example shows how to add some life to a view during animation by deforming the shape. 34 * As the button "falls", it stretches along the line of travel. When it hits the bottom, it 35 * squashes, like a real object when hitting a surface. Then the button reverses these actions 36 * to bounce back up to the start. 37 * 38 * Watch the associated video for this demo on the DevBytes channel of developer.android.com 39 * or on the DevBytes playlist in the androiddevelopers channel on YouTube at 40 * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0. 41 */ 42 public class SquashAndStretch extends Activity { 43 44 private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator(); 45 private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator(); 46 47 ViewGroup mContainer = null; 48 private static final long BASE_DURATION = 300; 49 private long sAnimatorScale = 1; 50 51 @Override onCreate(Bundle savedInstanceState)52 protected void onCreate(Bundle savedInstanceState) { 53 super.onCreate(savedInstanceState); 54 setContentView(R.layout.main); 55 56 mContainer = (ViewGroup) findViewById(R.id.container); 57 } 58 59 @Override onCreateOptionsMenu(Menu menu)60 public boolean onCreateOptionsMenu(Menu menu) { 61 getMenuInflater().inflate(R.menu.main, menu); 62 return true; 63 } 64 65 @Override onOptionsItemSelected(MenuItem item)66 public boolean onOptionsItemSelected(MenuItem item) { 67 if (item.getItemId() == R.id.menu_slow) { 68 sAnimatorScale = item.isChecked() ? 1 : 5; 69 item.setChecked(!item.isChecked()); 70 } 71 return super.onOptionsItemSelected(item); 72 } 73 onButtonClick(View view)74 public void onButtonClick(View view) { 75 long animationDuration = (long) (BASE_DURATION * sAnimatorScale); 76 77 // Scale around bottom/middle to simplify squash against the window bottom 78 view.setPivotX(view.getWidth() / 2); 79 view.setPivotY(view.getHeight()); 80 81 // Animate the button down, accelerating, while also stretching in Y and squashing in X 82 PropertyValuesHolder pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 83 mContainer.getHeight() - view.getHeight()); 84 PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, .7f); 85 PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.2f); 86 ObjectAnimator downAnim = ObjectAnimator.ofPropertyValuesHolder( 87 view, pvhTY, pvhSX, pvhSY); 88 downAnim.setInterpolator(sAccelerator); 89 downAnim.setDuration((long) (animationDuration * 2)); 90 91 // Stretch in X, squash in Y, then reverse 92 pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 2); 93 pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, .5f); 94 ObjectAnimator stretchAnim = 95 ObjectAnimator.ofPropertyValuesHolder(view, pvhSX, pvhSY); 96 stretchAnim.setRepeatCount(1); 97 stretchAnim.setRepeatMode(ValueAnimator.REVERSE); 98 stretchAnim.setInterpolator(sDecelerator); 99 stretchAnim.setDuration(animationDuration); 100 101 // Animate back to the start 102 pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0); 103 pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1); 104 pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1); 105 ObjectAnimator upAnim = 106 ObjectAnimator.ofPropertyValuesHolder(view, pvhTY, pvhSX, pvhSY); 107 upAnim.setDuration((long) (animationDuration * 2)); 108 upAnim.setInterpolator(sDecelerator); 109 110 AnimatorSet set = new AnimatorSet(); 111 set.playSequentially(downAnim, stretchAnim, upAnim); 112 set.start(); 113 } 114 } 115