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