Skip to content

Commit

Permalink
Updated curved motion to match new motion guidelines.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickbutcher committed May 14, 2016
1 parent 1e8142f commit 9cbc1df
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 9 deletions.
4 changes: 2 additions & 2 deletions app/src/main/java/io/plaidapp/ui/DesignerNewsStory.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.TextAppearanceSpan;
import android.transition.ArcMotion;
import android.transition.Transition;
import android.util.TypedValue;
import android.view.View;
Expand Down Expand Up @@ -84,6 +83,7 @@
import io.plaidapp.data.prefs.DesignerNewsPrefs;
import io.plaidapp.ui.drawable.ThreadedCommentDrawable;
import io.plaidapp.ui.transitions.FabDialogMorphSetup;
import io.plaidapp.ui.transitions.GravityArcMotion;
import io.plaidapp.ui.widget.AuthorTextView;
import io.plaidapp.ui.widget.CollapsingTitleLayout;
import io.plaidapp.ui.widget.ElasticDragDismissFrameLayout;
Expand Down Expand Up @@ -419,7 +419,7 @@ private void doFabExpand() {
.setDuration(fabExpandDuration);

// translate the placeholder ui back into position along an arc
ArcMotion arcMotion = new ArcMotion();
GravityArcMotion arcMotion = new GravityArcMotion();
arcMotion.setMinimumVerticalAngle(70f);
Path motionPath = arcMotion.getPath(translateX, translateY, 0, 0);
Animator position = ObjectAnimator.ofFloat(fabExpand, View.TRANSLATION_X, View
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/io/plaidapp/ui/HomeGridItemAnimator.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
import android.support.annotation.NonNull;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.transition.ArcMotion;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

import io.plaidapp.ui.recyclerview.SlideInItemAnimator;
import io.plaidapp.ui.transitions.GravityArcMotion;
import io.plaidapp.util.AnimUtils;
import io.plaidapp.util.ViewUtils;

Expand Down Expand Up @@ -80,7 +80,7 @@ public boolean animateChange(RecyclerView.ViewHolder oldHolder,
(holder.itemView.getWidth() - holder.pocket.getWidth()) / 2;
final int translatedTop =
initialTop - ((holder.itemView.getHeight() - holder.pocket.getHeight()) / 2);
final ArcMotion arc = new ArcMotion();
final GravityArcMotion arc = new GravityArcMotion();

// animate the title & pocket icon up, scale the pocket icon up
Animator titleMoveFadeOut = ObjectAnimator.ofPropertyValuesHolder(holder.title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.transition.ArcMotion;
import android.view.View;
import android.view.animation.Interpolator;

Expand Down Expand Up @@ -52,7 +51,7 @@ public static void setupSharedEelementTransitions(@NonNull Activity activity,
int startCornerRadius = activity.getIntent().getIntExtra
(EXTRA_SHARED_ELEMENT_START_CORNER_RADIUS, -1);

ArcMotion arcMotion = new ArcMotion();
GravityArcMotion arcMotion = new GravityArcMotion();
arcMotion.setMinimumHorizontalAngle(50f);
arcMotion.setMinimumVerticalAngle(50f);
int color = activity.getIntent().
Expand Down
214 changes: 214 additions & 0 deletions app/src/main/java/io/plaidapp/ui/transitions/GravityArcMotion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.plaidapp.ui.transitions;

import android.content.Context;
import android.graphics.Path;
import android.transition.ArcMotion;
import android.util.AttributeSet;

/**
* A tweak to {@link ArcMotion} which slightly alters the path calculation. In the real world
* gravity slows upward motion and accelerates downward motion. This class emulates this behavior
* to make motion paths appear more natural.
* <p>
* See https://www.google.com/design/spec/motion/movement.html#movement-movement-within-screen-bounds
*/
public class GravityArcMotion extends ArcMotion {

private static final float DEFAULT_MIN_ANGLE_DEGREES = 0;
private static final float DEFAULT_MAX_ANGLE_DEGREES = 70;
private static final float DEFAULT_MAX_TANGENT = (float)
Math.tan(Math.toRadians(DEFAULT_MAX_ANGLE_DEGREES/2));

private float mMinimumHorizontalAngle = 0;
private float mMinimumVerticalAngle = 0;
private float mMaximumAngle = DEFAULT_MAX_ANGLE_DEGREES;
private float mMinimumHorizontalTangent = 0;
private float mMinimumVerticalTangent = 0;
private float mMaximumTangent = DEFAULT_MAX_TANGENT;

public GravityArcMotion() {}

public GravityArcMotion(Context context, AttributeSet attrs) {
super(context, attrs);
}

/**
* @inheritDoc
*/
@Override
public void setMinimumHorizontalAngle(float angleInDegrees) {
mMinimumHorizontalAngle = angleInDegrees;
mMinimumHorizontalTangent = toTangent(angleInDegrees);
}

/**
* @inheritDoc
*/
@Override
public float getMinimumHorizontalAngle() {
return mMinimumHorizontalAngle;
}

/**
* @inheritDoc
*/
@Override
public void setMinimumVerticalAngle(float angleInDegrees) {
mMinimumVerticalAngle = angleInDegrees;
mMinimumVerticalTangent = toTangent(angleInDegrees);
}

/**
* @inheritDoc
*/
@Override
public float getMinimumVerticalAngle() {
return mMinimumVerticalAngle;
}

/**
* @inheritDoc
*/
@Override
public void setMaximumAngle(float angleInDegrees) {
mMaximumAngle = angleInDegrees;
mMaximumTangent = toTangent(angleInDegrees);
}

/**
* @inheritDoc
*/
@Override
public float getMaximumAngle() {
return mMaximumAngle;
}

private static float toTangent(float arcInDegrees) {
if (arcInDegrees < 0 || arcInDegrees > 90) {
throw new IllegalArgumentException("Arc must be between 0 and 90 degrees");
}
return (float) Math.tan(Math.toRadians(arcInDegrees / 2));
}

@Override
public Path getPath(float startX, float startY, float endX, float endY) {
// Here's a little ascii art to show how this is calculated:
// c---------- b
// \ / |
// \ d |
// \ / e
// a----f
// This diagram assumes that the horizontal distance is less than the vertical
// distance between The start point (a) and end point (b).
// d is the midpoint between a and b. c is the center point of the circle with
// This path is formed by assuming that start and end points are in
// an arc on a circle. The end point is centered in the circle vertically
// and start is a point on the circle.

// Triangles bfa and bde form similar right triangles. The control points
// for the cubic Bezier arc path are the midpoints between a and e and e and b.

Path path = new Path();
path.moveTo(startX, startY);

float ex;
float ey;
if (startY == endY) {
ex = (startX + endX) / 2;
ey = startY + mMinimumHorizontalTangent * Math.abs(endX - startX) / 2;
} else if (startX == endX) {
ex = startX + mMinimumVerticalTangent * Math.abs(endY - startY) / 2;
ey = (startY + endY) / 2;
} else {
float deltaX = endX - startX;

/**
* This is the only change to ArcMotion
*/
float deltaY;
if (endY < startY) {
deltaY = startY - endY; // Y is inverted compared to diagram above.
} else {
deltaY = endY - startY;
}
/**
* End changes
*/

// hypotenuse squared.
float h2 = deltaX * deltaX + deltaY * deltaY;

// Midpoint between start and end
float dx = (startX + endX) / 2;
float dy = (startY + endY) / 2;

// Distance squared between end point and mid point is (1/2 hypotenuse)^2
float midDist2 = h2 * 0.25f;

float minimumArcDist2 = 0;

if (Math.abs(deltaX) < Math.abs(deltaY)) {
// Similar triangles bfa and bde mean that (ab/fb = eb/bd)
// Therefore, eb = ab * bd / fb
// ab = hypotenuse
// bd = hypotenuse/2
// fb = deltaY
float eDistY = h2 / (2 * deltaY);
ey = endY + eDistY;
ex = endX;

minimumArcDist2 = midDist2 * mMinimumVerticalTangent
* mMinimumVerticalTangent;
} else {
// Same as above, but flip X & Y
float eDistX = h2 / (2 * deltaX);
ex = endX + eDistX;
ey = endY;

minimumArcDist2 = midDist2 * mMinimumHorizontalTangent
* mMinimumHorizontalTangent;
}
float arcDistX = dx - ex;
float arcDistY = dy - ey;
float arcDist2 = arcDistX * arcDistX + arcDistY * arcDistY;

float maximumArcDist2 = midDist2 * mMaximumTangent * mMaximumTangent;

float newArcDistance2 = 0;
if (arcDist2 < minimumArcDist2) {
newArcDistance2 = minimumArcDist2;
} else if (arcDist2 > maximumArcDist2) {
newArcDistance2 = maximumArcDist2;
}
if (newArcDistance2 != 0) {
float ratio2 = newArcDistance2 / arcDist2;
float ratio = (float) Math.sqrt(ratio2);
ex = dx + (ratio * (ex - dx));
ey = dy + (ratio * (ey - dy));
}
}
float controlX1 = (startX + ex) / 2;
float controlY1 = (startY + ey) / 2;
float controlX2 = (ex + endX) / 2;
float controlY2 = (ey + endY) / 2;
path.cubicTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
return path;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<targets>
<target android:targetId="@id/story_title_background" />
</targets>
<arcMotion />
<pathMotion class="io.plaidapp.ui.transitions.GravityArcMotion" />
</transition>

</transitionSet>
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<targets>
<target android:targetId="@id/story_title_background" />
</targets>
<arcMotion />
<pathMotion class="io.plaidapp.ui.transitions.GravityArcMotion" />
</changeBounds>

</transitionSet>
4 changes: 3 additions & 1 deletion app/src/main/res/transition/dribbble_player_shared_enter.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
android:transitionOrdering="together">

<changeBounds />
<arcMotion android:maximumAngle="50" />
<pathMotion
class="io.plaidapp.ui.transitions.GravityArcMotion"
android:maximumAngle="50" />
<transition
class="io.plaidapp.ui.transitions.LiftOff"
android:elevation="@dimen/touch_raise" />
Expand Down

0 comments on commit 9cbc1df

Please sign in to comment.