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