1 /*
2  * Copyright (C) 2017 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.support.animation;
18 
19 import android.app.Activity;
20 import android.os.Bundle;
21 import android.view.MotionEvent;
22 import android.view.VelocityTracker;
23 import android.view.View;
24 import android.widget.SeekBar;
25 import android.widget.TextView;
26 
27 import androidx.dynamicanimation.animation.DynamicAnimation;
28 import androidx.dynamicanimation.animation.SpringAnimation;
29 
30 /**
31  * Activity for chained spring animations.
32  */
33 public class MainActivity extends Activity {
34     private float mDampingRatio = 1.0f;
35     private float mStiffness = 50.0f;
36 
37     @Override
onCreate(Bundle savedInstanceState)38     protected void onCreate(Bundle savedInstanceState) {
39         super.onCreate(savedInstanceState);
40         setContentView(R.layout.activity_chained_springs);
41         final View lead = findViewById(R.id.lead);
42         final View follow1 = findViewById(R.id.follow1);
43         final View follow2 = findViewById(R.id.follow2);
44 
45         final SpringAnimation anim1X = new SpringAnimation(follow1, DynamicAnimation.TRANSLATION_X,
46                 lead.getTranslationX());
47         final SpringAnimation anim1Y = new SpringAnimation(follow1, DynamicAnimation.TRANSLATION_Y,
48                 lead.getTranslationY());
49         final SpringAnimation anim2X = new SpringAnimation(follow2, DynamicAnimation.TRANSLATION_X,
50                 follow1.getTranslationX());
51         final SpringAnimation anim2Y = new SpringAnimation(follow2, DynamicAnimation.TRANSLATION_Y,
52                 follow1.getTranslationY());
53 
54         anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
55             @Override
56             public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
57                                           float velocity) {
58                 anim2X.animateToFinalPosition(value);
59             }
60         });
61 
62         anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
63             @Override
64             public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
65                                           float velocity) {
66                 anim2Y.animateToFinalPosition(value);
67             }
68         });
69 
70         ((View) lead.getParent()).setOnTouchListener(new View.OnTouchListener() {
71             public float firstDownX = 0;
72             public float firstDownY = 0;
73             public VelocityTracker tracker;
74             @Override
75             public boolean onTouch(View view, MotionEvent motionEvent) {
76                 if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
77 
78                     if (motionEvent.getX() < lead.getX()
79                             || motionEvent.getX() > lead.getX() + lead.getWidth()
80                             || motionEvent.getY() < lead.getY()
81                             || motionEvent.getY() > lead.getY() + lead.getHeight()) {
82                         return false;
83                     }
84 
85                     // Update the stiffness and damping ratio that are configured by user from the
86                     // seekbar UI as needed.
87                     anim1X.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
88                     anim1Y.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
89                     anim2X.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
90                     anim2Y.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
91 
92                     firstDownX = motionEvent.getX() - lead.getTranslationX();
93                     firstDownY = motionEvent.getY() - lead.getTranslationY();
94                     tracker = VelocityTracker.obtain();
95                     tracker.clear();
96                     tracker.addMovement(motionEvent);
97                 } else if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
98                     float deltaX = motionEvent.getX() - firstDownX;
99                     float deltaY = motionEvent.getY() - firstDownY;
100 
101                     // Directly manipulate the lead view.
102                     lead.setTranslationX(deltaX);
103                     lead.setTranslationY(deltaY);
104 
105                     // Animate the follow views to the new final position
106                     anim1X.animateToFinalPosition(deltaX);
107                     anim1Y.animateToFinalPosition(deltaY);
108 
109                     tracker.addMovement(motionEvent);
110                 }
111                 return true;
112             }
113         });
114         setupSeekBars();
115     }
116 
117     // Setup seek bars so damping ratio and stiffness for the spring can be modified through the UI.
setupSeekBars()118     void setupSeekBars() {
119         SeekBar dr = findViewById(R.id.damping_ratio);
120         dr.setMax(130);
121         final TextView drTxt = findViewById(R.id.damping_ratio_txt);
122         dr.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
123             @Override
124             public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
125                 if (i < 80) {
126                     mDampingRatio = i / 80.0f;
127                 } else if (i > 90) {
128                     mDampingRatio = (float) Math.exp((i - 90) / 10.0);
129                 } else {
130                     mDampingRatio = 1;
131                 }
132                 drTxt.setText(String.format("%.4f", (float) mDampingRatio));
133             }
134 
135             @Override
136             public void onStartTrackingTouch(SeekBar seekBar) {
137 
138             }
139 
140             @Override
141             public void onStopTrackingTouch(SeekBar seekBar) {
142 
143             }
144         });
145 
146         SeekBar stiff = findViewById(R.id.stiffness);
147         stiff.setMax(110);
148         final TextView nfTxt = findViewById(R.id.stiffness_txt);
149         stiff.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
150             @Override
151             public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
152                 float stiffness = (float) Math.exp(i / 10d);
153                 mStiffness = stiffness;
154                 nfTxt.setText(String.format("%.3f", (float) stiffness));
155             }
156 
157             @Override
158             public void onStartTrackingTouch(SeekBar seekBar) {
159 
160             }
161 
162             @Override
163             public void onStopTrackingTouch(SeekBar seekBar) {
164 
165             }
166         });
167         dr.setProgress(80);
168         stiff.setProgress(60);
169 
170     }
171 }
172