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