Last active
August 29, 2015 14:06
-
-
Save willbailey/2519033819f2931e688c to your computer and use it in GitHub Desktop.
SpringChain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This file provided by Facebook is for non-commercial testing and evaluation purposes only. | |
* Facebook reserves all rights not expressly granted. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
*/ | |
package com.facebook.rebound; | |
import java.util.concurrent.CopyOnWriteArrayList; | |
/** | |
* This class makes it easy to create a cascading chain of springs. You choose one Spring to be the | |
* control spring by calling setControlSpring then all the springs above and below the control spring | |
* in the list will trail it. | |
* | |
* Here's a demo: | |
* http://youtu.be/h9F7iKogkaY | |
*/ | |
public class SpringChain implements SpringListener { | |
private final SpringSystem mSpringSystem; | |
private final CopyOnWriteArrayList<SpringListener> mListeners; | |
private final CopyOnWriteArrayList<Spring> mSprings; | |
private static final SpringConfig ATTACHMENT_SPRING = SpringConfig.fromOrigamiTensionAndFriction(70, 10); | |
private static final SpringConfig MAIN_SPRING = SpringConfig.fromOrigamiTensionAndFriction(40, 6); | |
private int mControlSpringIndex; | |
static { | |
SpringConfigRegistry.getInstance().addSpringConfig(MAIN_SPRING, "main spring"); | |
SpringConfigRegistry.getInstance().addSpringConfig(ATTACHMENT_SPRING, "attachment spring"); | |
} | |
public static SpringChain create() { | |
return new SpringChain(); | |
} | |
public SpringChain() { | |
mSpringSystem = SpringSystem.create(); | |
mListeners = new CopyOnWriteArrayList<SpringListener>(); | |
mSprings = new CopyOnWriteArrayList<Spring>(); | |
} | |
/** | |
* Add a spring to the chain that will callback to the provided listener. | |
* @param listener the listener to notify for this Spring in the chain | |
* @return this SpringChain for chaining | |
*/ | |
public SpringChain addSpring(final SpringListener listener) { | |
// We listen to each spring added to the SpringChain and dynamically chain the springs together | |
// whenever the control spring state is modified. | |
Spring spring = mSpringSystem | |
.createSpring() | |
.addListener(this) | |
.setSpringConfig(ATTACHMENT_SPRING); | |
mSprings.add(spring); | |
mListeners.add(listener); | |
return this; | |
} | |
/** | |
* Set the index of the control spring. This spring will drive the positions of all the springs | |
* before and after it in the list when moved. | |
* @param i the index to use for the control spring | |
* @return this SpringChain for chaining | |
*/ | |
public SpringChain setControlSpringIndex(int i) { | |
mControlSpringIndex = i; | |
for (Spring spring : mSpringSystem.getAllSprings()) { | |
spring.setSpringConfig(ATTACHMENT_SPRING); | |
} | |
getControlSpring().setSpringConfig(MAIN_SPRING); | |
return this; | |
} | |
/** | |
* Retrieve the control spring so you can manipulate it to drive the positions of the other | |
* springs. | |
* @return the control spring. | |
*/ | |
public Spring getControlSpring() { | |
return mSprings.get(mControlSpringIndex); | |
} | |
@Override | |
public void onSpringUpdate(Spring spring) { | |
// Get the control spring index and update the endValue of each spring above and below it in the | |
// spring collection triggering a cascading effect. | |
int idx = mSprings.indexOf(spring); | |
SpringListener listener = mListeners.get(idx); | |
int above = -1; | |
int below = -1; | |
if (idx == mControlSpringIndex) { | |
below = idx - 1; | |
above = idx + 1; | |
} else if (idx < mControlSpringIndex) { | |
below = idx - 1; | |
} else if (idx > mControlSpringIndex) { | |
above = idx + 1; | |
} | |
if (above > -1 && above < mSprings.size()) { | |
mSprings.get(above).setEndValue(spring.getCurrentValue()); | |
} | |
if (below > -1 && below < mSprings.size()) { | |
mSprings.get(below).setEndValue(spring.getCurrentValue()); | |
} | |
listener.onSpringUpdate(spring); | |
} | |
@Override | |
public void onSpringAtRest(Spring spring) { | |
int idx = mSprings.indexOf(spring); | |
mListeners.get(idx).onSpringAtRest(spring); | |
} | |
@Override | |
public void onSpringActivate(Spring spring) { | |
int idx = mSprings.indexOf(spring); | |
mListeners.get(idx).onSpringActivate(spring); | |
} | |
@Override | |
public void onSpringEndStateChange(Spring spring) { | |
int idx = mSprings.indexOf(spring); | |
mListeners.get(idx).onSpringEndStateChange(spring); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment