Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sping #199

Merged
merged 9 commits into from Mar 31, 2021
Merged

Sping #199

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -16,6 +16,8 @@

package androidx.constraintlayout.motion.utils;

import androidx.constraintlayout.core.motion.utils.SpringStopEngine;
import androidx.constraintlayout.core.motion.utils.StopEngine;
import androidx.constraintlayout.core.motion.utils.StopLogicEngine;
import androidx.constraintlayout.motion.widget.MotionInterpolator;

Expand All @@ -28,7 +30,9 @@
* @hide
*/
public class StopLogic extends MotionInterpolator {
private StopLogicEngine engine = new StopLogicEngine();
private StopLogicEngine mStopLogicEngine = new StopLogicEngine();
private SpringStopEngine mSpringStopEngine;
private StopEngine mEngine = mStopLogicEngine;

/**
* Debugging logic to log the state.
Expand All @@ -39,24 +43,56 @@ public class StopLogic extends MotionInterpolator {
*/

public String debug(String desc, float time) {
return engine.debug(desc, time);
return mEngine.debug(desc, time);
}

public float getVelocity(float x) {
return engine.getVelocity(x);
return mEngine.getVelocity(x);
}

public void config(float currentPos, float destination, float currentVelocity, float maxTime, float maxAcceleration, float maxVelocity) {
engine.config(currentPos, destination, currentVelocity, maxTime, maxAcceleration, maxVelocity);
mEngine = mStopLogicEngine;
mStopLogicEngine.config(currentPos, destination, currentVelocity, maxTime, maxAcceleration, maxVelocity);
}

/**
* This configure the stop logic to be a spring.
* Moving from currentPosition(P0) to destination with an initial velocity of currentVelocity (V0)
* moving as if it has a mass (m) with spring constant stiffness(k), and friction(c)
* It moves with the equation acceleration a = (-k.x-c.v)/m.
* x = current position - destination
* v is velocity
*
* @param currentPos The current position
* @param destination The destination position
* @param currentVelocity the initial velocity
* @param mass the mass
* @param stiffness the stiffness or spring constant (the force by which the spring pulls)
* @param damping the stiffness or spring constant. (the resistance to the motion)
* @param stopThreshold (When the max velocity of the movement is below this it stops)
* @param boundaryMode This will allow you to control if it overshoots or bounces when it hits 0 and 1
*/
public void springConfig(float currentPos, float destination, float currentVelocity,
jafu888 marked this conversation as resolved.
Show resolved Hide resolved
float mass, float stiffness, float damping, float stopThreshold,
int boundaryMode) {
if (mSpringStopEngine == null) {
mSpringStopEngine = new SpringStopEngine();
}
mEngine = mSpringStopEngine;
mSpringStopEngine.springConfig(currentPos, destination, currentVelocity, mass, stiffness, damping, stopThreshold, boundaryMode);
}

@Override
public float getInterpolation(float v) {
return engine.getInterpolation(v);
return mEngine.getInterpolation(v);
}

@Override
public float getVelocity() {
return engine.getVelocity();
return mEngine.getVelocity();
}

public boolean isStopped() {
return mEngine.isStopped();
}
}
Expand Up @@ -998,6 +998,8 @@ public class MotionLayout extends ConstraintLayout implements
public static final int TOUCH_UP_STOP = 3;
public static final int TOUCH_UP_DECELERATE = 4;
public static final int TOUCH_UP_DECELERATE_AND_COMPLETE = 5;
public static final int TOUCH_UP_NEVER_TO_START = 6;
public static final int TOUCH_UP_NEVER_TO_END = 7;

static final String TAG = "MotionLayout";
private final static boolean DEBUG = false;
Expand Down Expand Up @@ -1888,15 +1890,24 @@ public void touchAnimateTo(int touchUpMode, float position, float currentVelocit

switch (touchUpMode) {
case TOUCH_UP_COMPLETE:
case TOUCH_UP_NEVER_TO_START:
case TOUCH_UP_NEVER_TO_END:
case TOUCH_UP_COMPLETE_TO_START:
case TOUCH_UP_COMPLETE_TO_END: {
if (touchUpMode == TOUCH_UP_COMPLETE_TO_START) {
if (touchUpMode == TOUCH_UP_COMPLETE_TO_START || touchUpMode == TOUCH_UP_NEVER_TO_END) {
position = 0;
} else if (touchUpMode == TOUCH_UP_COMPLETE_TO_END) {
} else if (touchUpMode == TOUCH_UP_COMPLETE_TO_END || touchUpMode == TOUCH_UP_NEVER_TO_START) {
position = 1;
}
mStopLogic.config(mTransitionLastPosition, position, currentVelocity,
mTransitionDuration, mScene.getMaxAcceleration(), mScene.getMaxVelocity());
float stiff = mScene.getSpringStiffiness();
if(Float.isNaN(stiff)) {
jafu888 marked this conversation as resolved.
Show resolved Hide resolved
mStopLogic.config(mTransitionLastPosition, position, currentVelocity,
mTransitionDuration, mScene.getMaxAcceleration(), mScene.getMaxVelocity());
} else {
mStopLogic.springConfig(mTransitionLastPosition, position, currentVelocity,
mScene.getSpringMass(), mScene.getSpringStiffiness(), mScene.getSpringDamping(),
mScene.getSpringStopThreshold(), mScene.getSpringBoundary());
}

int currentState = mCurrentState; // TODO: we really should remove setProgress(), this is a temporary fix
mTransitionGoalPosition = position;
Expand Down Expand Up @@ -1935,6 +1946,46 @@ public void touchAnimateTo(int touchUpMode, float position, float currentVelocit
invalidate();
}

/**
* Allows you to use trigger spring motion touch behaviour.
* You must have configured all the spring parameters in the Transition's OnSwipe
*
* @param position the position 0 - 1
* @param currentVelocity the current velocity rate of change in position per second
*/
public void touchSpringTo(float position, float currentVelocity) {
jafu888 marked this conversation as resolved.
Show resolved Hide resolved
if (DEBUG) {
Log.v(TAG, " " + Debug.getLocation() + " touchAnimateTo " + position + " " + currentVelocity);
}
if (mScene == null) {
return;
}
if (mTransitionLastPosition == position) {
return;
}

mTemporalInterpolator = true;
mAnimationStartTime = getNanoTime();
mTransitionDuration = mScene.getDuration() / 1000f;

mTransitionGoalPosition = position;
mInTransition = true;

mStopLogic.springConfig(mTransitionLastPosition, position, currentVelocity,
mScene.getSpringMass(), mScene.getSpringStiffiness(), mScene.getSpringDamping(),
mScene.getSpringStopThreshold(), mScene.getSpringBoundary());

int currentState = mCurrentState; // TODO: we really should remove setProgress(), this is a temporary fix
mTransitionGoalPosition = position;
mCurrentState = currentState;
mInterpolator = mStopLogic;


mTransitionInstantly = false;
mAnimationStartTime = getNanoTime();
invalidate();
}

private static boolean willJump(float velocity, float position, float maxAcceleration) {
if (velocity > 0) {
float time = velocity / maxAcceleration;
Expand Down Expand Up @@ -2158,6 +2209,25 @@ public boolean isInRotation() {
return mInRotation;
}

/**
* This jumps to a state
* It will be at that state after one repaint cycle
* If the current transition contains that state.
* It setsProgress 0 or 1 to that state.
* If not in the current transition itsl
*
* @param id state to set
*/
public void jumpToState(int id) {
if (mBeginState == id) {
setProgress(0);
} else if (mEndState == id) {
setProgress(1);
} else {
setTransition(id, id);
}
}

/**
* Animate to the state defined by the id.
* Width and height may be used in the picking of the id using this StateSet.
Expand Down Expand Up @@ -2195,10 +2265,16 @@ public void transitionToState(int id, int screenWidth, int screenHeight, int dur
}
if (mBeginState == id) {
animateTo(0.0f);
if (duration > 0) {
mTransitionDuration = duration / 1000f;
}
return;
}
if (mEndState == id) {
animateTo(1.0f);
if (duration > 0) {
mTransitionDuration = duration / 1000f;
}
return;
}
mEndState = id;
Expand Down Expand Up @@ -3500,11 +3576,19 @@ void evaluate(boolean force) {
mTransitionLastPosition = position;
mTransitionPosition = position;
mTransitionLastTime = currentTime;

int NOT_STOP_LOGIC = 0;
int STOP_LOGIC_CONTINUE = 1;
int STOP_LOGIC_STOP = 2;
int stopLogicDone = NOT_STOP_LOGIC;
if (mInterpolator != null && !done) {
if (mTemporalInterpolator) {
float time = (currentTime - mAnimationStartTime) * 1E-9f;
position = mInterpolator.getInterpolation(time);
if (mInterpolator == mStopLogic) {
boolean dp = mStopLogic.isStopped();
stopLogicDone = (dp)?STOP_LOGIC_STOP:STOP_LOGIC_CONTINUE;
}

if (DEBUG) {
Log.v(TAG, Debug.getLocation() + " mTransitionLastPosition = " + mTransitionLastPosition + " position = " + position);
}
Expand All @@ -3514,7 +3598,7 @@ void evaluate(boolean force) {
if (mInterpolator instanceof MotionInterpolator) {
float lastVelocity = ((MotionInterpolator) mInterpolator).getVelocity();
mLastVelocity = lastVelocity;
if (Math.abs(lastVelocity) * mTransitionDuration <= EPSILON) {
if (Math.abs(lastVelocity) * mTransitionDuration <= EPSILON && stopLogicDone==STOP_LOGIC_STOP) {
mInTransition = false;
}
if (lastVelocity > 0 && position >= 1.0f) {
Expand Down Expand Up @@ -3544,15 +3628,17 @@ void evaluate(boolean force) {
setState(TransitionState.MOVING);
}

if ((dir > 0 && position >= mTransitionGoalPosition)
|| (dir <= 0 && position <= mTransitionGoalPosition)) {
position = mTransitionGoalPosition;
mInTransition = false;
}
if ( stopLogicDone != STOP_LOGIC_CONTINUE) {
if ((dir > 0 && position >= mTransitionGoalPosition)
|| (dir <= 0 && position <= mTransitionGoalPosition)) {
position = mTransitionGoalPosition;
mInTransition = false;
}

if (position >= 1.0f || position <= 0.0f) {
mInTransition = false;
setState(TransitionState.FINISHED);
if (position >= 1.0f || position <= 0.0f) {
mInTransition = false;
setState(TransitionState.FINISHED);
}
}

int n = getChildCount();
Expand Down Expand Up @@ -3994,7 +4080,10 @@ public boolean onTouchEvent(MotionEvent event) {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
mPreviouseRotation = getDisplay().getRotation();
Display display = getDisplay();
if (display != null) {
mPreviouseRotation = display.getRotation();
}
}
if (mScene != null && mCurrentState != UNSET) {
ConstraintSet cSet = mScene.getConstraintSet(mCurrentState);
Expand Down
Expand Up @@ -455,6 +455,7 @@ public boolean isViewTransitionEnabled(int id) {
public boolean applyViewTransition(int viewTransitionId, MotionController motionController) {
return mViewTransitionController.applyViewTransition(viewTransitionId, motionController);
}

///////////////////////////////////////////////////////////////////////////////
// ====================== Transition ==========================================

Expand Down Expand Up @@ -758,7 +759,8 @@ public TransitionOnClick(Context context, Transition transition, XmlPullParser p
}
a.recycle();
}
public TransitionOnClick( Transition transition, int id, int action) {

public TransitionOnClick(Transition transition, int id, int action) {
mTransition = transition;
mTargetId = id;
mMode = action;
Expand Down Expand Up @@ -1664,6 +1666,40 @@ float getMaxVelocity() {
return 0;
}

float getSpringStiffiness() {
if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {
return mCurrentTransition.mTouchResponse.getSpringStiffness();
}
return 0;
}

float getSpringMass() {
if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {
return mCurrentTransition.mTouchResponse.getSpringMass();
}
return 0;
}

float getSpringDamping() {
if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {
return mCurrentTransition.mTouchResponse.getSpringDamping();
}
return 0;
}

float getSpringStopThreshold() {
if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {
return mCurrentTransition.mTouchResponse.getSpringStopThreshold();
}
return 0;
}
int getSpringBoundary() {
if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {
return mCurrentTransition.mTouchResponse.getSpringBoundary();
}
return 0;
}

void setupTouch() {
if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {
mCurrentTransition.mTouchResponse.setupTouch();
Expand Down