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