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 * This is a single spring animation. It provides a UI to interact with the spring, and two seek
31 * bars to tune the spring constants.
32 */
33public class SpringActivity extends Activity {
34    private float mDampingRatio;
35    private float mStiffness;
36    private SpringView mSpringView;
37
38    @Override
39    protected void onCreate(Bundle savedInstanceState) {
40        super.onCreate(savedInstanceState);
41        setContentView(R.layout.activity_main);
42
43        final View v = findViewById(R.id.container);
44        mSpringView = findViewById(R.id.actual_spring);
45
46        final View img = findViewById(R.id.imageView);
47        setupSeekBars();
48        final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y,
49                0 /* final position */);
50        anim.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
51            @Override
52            public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {
53                // Update the drawing of the spring.
54                mSpringView.setMassHeight(img.getY());
55            }
56        });
57
58        ((View) img.getParent()).setOnTouchListener(new View.OnTouchListener() {
59            public float touchOffset;
60            public VelocityTracker vt;
61            @Override
62            public boolean onTouch(View v, MotionEvent motionEvent) {
63                if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
64                    // check whether the touch happens inside of the img view.
65                    boolean inside = motionEvent.getX() >= img.getX()
66                            && motionEvent.getX() <= img.getX() + img.getWidth()
67                            && motionEvent.getY() >= img.getY()
68                            && motionEvent.getY() <= img.getY() + img.getHeight();
69
70                    anim.cancel();
71
72                    if (!inside) {
73                        return false;
74                    }
75                    // Apply this offset to all the subsequent events
76                    touchOffset = img.getTranslationY() - motionEvent.getY();
77                    vt = VelocityTracker.obtain();
78                    vt.clear();
79                }
80
81                vt.addMovement(motionEvent);
82
83                if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
84                    img.setTranslationY(motionEvent.getY() + touchOffset);
85                    // Updates the drawing of the spring.
86                    mSpringView.setMassHeight(img.getY());
87                } else if (motionEvent.getActionMasked() == MotionEvent.ACTION_CANCEL
88                        || motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
89                    // Compute the velocity in unit: pixel/second
90                    vt.computeCurrentVelocity(1000);
91                    float velocity = vt.getYVelocity();
92                    anim.getSpring().setDampingRatio(mDampingRatio).setStiffness(mStiffness);
93                    anim.setStartVelocity(velocity).start();
94                    vt.recycle();
95                }
96                return true;
97            }
98        });
99    }
100
101    // Setup seek bars so damping ratio and stiffness for the spring can be modified through the UI.
102    void setupSeekBars() {
103        SeekBar dr = findViewById(R.id.damping_ratio);
104        dr.setMax(130);
105        final TextView drTxt = findViewById(R.id.damping_ratio_txt);
106        dr.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
107            @Override
108            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
109                if (i < 80) {
110                    mDampingRatio = i / 80.0f;
111                } else if (i > 90) {
112                    mDampingRatio = (float) Math.exp((i - 90) / 10.0);
113                } else {
114                    mDampingRatio = 1;
115                }
116                drTxt.setText(String.format("%.4f", (float) mDampingRatio));
117            }
118
119            @Override
120            public void onStartTrackingTouch(SeekBar seekBar) {
121
122            }
123
124            @Override
125            public void onStopTrackingTouch(SeekBar seekBar) {
126
127            }
128        });
129
130        SeekBar stiff = findViewById(R.id.stiffness);
131        stiff.setMax(110);
132        final TextView nfTxt = findViewById(R.id.stiffness_txt);
133        stiff.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
134            @Override
135            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
136                float stiffness = (float) Math.exp(i / 10d);
137                mStiffness = stiffness;
138                nfTxt.setText(String.format("%.3f", (float) stiffness));
139            }
140
141            @Override
142            public void onStartTrackingTouch(SeekBar seekBar) {
143
144            }
145
146            @Override
147            public void onStopTrackingTouch(SeekBar seekBar) {
148
149            }
150        });
151        dr.setProgress(40);
152        stiff.setProgress(60);
153    }
154}
155