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