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