Cleaning up some reordering issues:

-> Reorder solution should never change unless target cell changes
-> Simplified code and improved the behaviour when items' jiggle
   animations switch from one direction to another. These transitions
   are now seamless and have no more strange delays.

Change-Id: I35d70f275d622501851328584bfcb46eec91ff3b
This commit is contained in:
Adam Cohen
2012-05-23 18:26:45 -07:00
parent 56734d7e86
commit d024f9845a
2 changed files with 35 additions and 54 deletions
+30 -46
View File
@@ -1902,7 +1902,6 @@ public class CellLayout extends ViewGroup {
// This method starts or changes the reorder hint animations // This method starts or changes the reorder hint animations
private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) { private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
int childCount = mShortcutsAndWidgets.getChildCount(); int childCount = mShortcutsAndWidgets.getChildCount();
int timeForPriorAnimationToComplete = getMaxCompletionTime();
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
View child = mShortcutsAndWidgets.getChildAt(i); View child = mShortcutsAndWidgets.getChildAt(i);
if (child == dragView) continue; if (child == dragView) continue;
@@ -1911,7 +1910,7 @@ public class CellLayout extends ViewGroup {
if (c != null) { if (c != null) {
ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY, ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
c.x, c.y, c.spanX, c.spanY); c.x, c.y, c.spanX, c.spanY);
rha.animate(timeForPriorAnimationToComplete); rha.animate();
} }
} }
} }
@@ -1920,11 +1919,13 @@ public class CellLayout extends ViewGroup {
// in a temporary state, and hint at where the item will return to. // in a temporary state, and hint at where the item will return to.
class ReorderHintAnimation { class ReorderHintAnimation {
View child; View child;
float deltaX; float finalDeltaX;
float deltaY; float finalDeltaY;
float initDeltaX;
float initDeltaY;
float finalScale;
float initScale;
private static final int DURATION = 300; private static final int DURATION = 300;
private int repeatCount;
private boolean cancelOnCycleComplete = false;
ValueAnimator va; ValueAnimator va;
public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1, public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
@@ -1937,72 +1938,73 @@ public class CellLayout extends ViewGroup {
final int y1 = mTmpPoint[1]; final int y1 = mTmpPoint[1];
final int dX = x1 - x0; final int dX = x1 - x0;
final int dY = y1 - y0; final int dY = y1 - y0;
deltaX = 0; finalDeltaX = 0;
deltaY = 0; finalDeltaY = 0;
if (dX == dY && dX == 0) { if (dX == dY && dX == 0) {
} else { } else {
if (dY == 0) { if (dY == 0) {
deltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude; finalDeltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude;
} else if (dX == 0) { } else if (dX == 0) {
deltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude; finalDeltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude;
} else { } else {
double angle = Math.atan( (float) (dY) / dX); double angle = Math.atan( (float) (dY) / dX);
deltaX = (int) (- Math.signum(dX) * finalDeltaX = (int) (- Math.signum(dX) *
Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude)); Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude));
deltaY = (int) (- Math.signum(dY) * finalDeltaY = (int) (- Math.signum(dY) *
Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude)); Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude));
} }
} }
initDeltaX = child.getTranslationX();
initDeltaY = child.getTranslationY();
finalScale = 1.0f - 4.0f / child.getWidth();
initScale = child.getScaleX();
child.setPivotY(child.getMeasuredHeight() * 0.5f); child.setPivotY(child.getMeasuredHeight() * 0.5f);
child.setPivotX(child.getMeasuredWidth() * 0.5f); child.setPivotX(child.getMeasuredWidth() * 0.5f);
this.child = child; this.child = child;
} }
void animate(int delay) { void animate() {
if (mShakeAnimators.containsKey(child)) { if (mShakeAnimators.containsKey(child)) {
ReorderHintAnimation oldAnimation = mShakeAnimators.get(child); ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
oldAnimation.completeAnimation(); oldAnimation.cancel();
mShakeAnimators.remove(child); mShakeAnimators.remove(child);
} }
if (deltaX == 0 && deltaY == 0) { if (finalDeltaX == 0 && finalDeltaY == 0) {
return; return;
} }
va = ValueAnimator.ofFloat(0f, 1f); va = ValueAnimator.ofFloat(0f, 1f);
va.setRepeatMode(ValueAnimator.REVERSE); va.setRepeatMode(ValueAnimator.REVERSE);
va.setRepeatCount(ValueAnimator.INFINITE); va.setRepeatCount(ValueAnimator.INFINITE);
va.setDuration(DURATION); va.setDuration(DURATION);
va.setStartDelay((int) ((Math.max(REORDER_ANIMATION_DURATION, delay) va.setStartDelay((int) (Math.random() * 60));
+ Math.random() * 60)));
va.addUpdateListener(new AnimatorUpdateListener() { va.addUpdateListener(new AnimatorUpdateListener() {
@Override @Override
public void onAnimationUpdate(ValueAnimator animation) { public void onAnimationUpdate(ValueAnimator animation) {
float r = ((Float) animation.getAnimatedValue()).floatValue(); float r = ((Float) animation.getAnimatedValue()).floatValue();
float x = r * deltaX; float x = r * finalDeltaX + (1 - r) * initDeltaX;
float y = r * deltaY; float y = r * finalDeltaY + (1 - r) * initDeltaY;
child.setTranslationX(x); child.setTranslationX(x);
child.setTranslationY(y); child.setTranslationY(y);
float sf = 4.0f / child.getWidth(); float s = r * finalScale + (1 - r) * initScale;
float s = 1.0f - r * sf;
child.setScaleX(s); child.setScaleX(s);
child.setScaleY(s); child.setScaleY(s);
} }
}); });
va.addListener(new AnimatorListenerAdapter() { va.addListener(new AnimatorListenerAdapter() {
public void onAnimationRepeat(Animator animation) { public void onAnimationRepeat(Animator animation) {
repeatCount++;
// We make sure to end only after a full period // We make sure to end only after a full period
if (cancelOnCycleComplete && repeatCount % 2 == 0) { initDeltaX = 0;
va.cancel(); initDeltaY = 0;
} initScale = 1.0f;
} }
}); });
mShakeAnimators.put(child, this); mShakeAnimators.put(child, this);
va.start(); va.start();
} }
private void cancel() {
private void completeAnimation() { va.cancel();
cancelOnCycleComplete = true;
} }
private void completeAnimationImmediately() { private void completeAnimationImmediately() {
va.cancel(); va.cancel();
@@ -2018,16 +2020,6 @@ public class CellLayout extends ViewGroup {
s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
s.start(); s.start();
} }
// Returns the time required to complete the current oscillating animation
private int completionTime() {
if (repeatCount % 2 == 0) {
return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION);
} else {
return (int) (va.getDuration() - va.getCurrentPlayTime());
}
}
} }
private void completeAndClearReorderHintAnimations() { private void completeAndClearReorderHintAnimations() {
@@ -2037,14 +2029,6 @@ public class CellLayout extends ViewGroup {
mShakeAnimators.clear(); mShakeAnimators.clear();
} }
private int getMaxCompletionTime() {
int maxTime = 0;
for (ReorderHintAnimation a: mShakeAnimators.values()) {
maxTime = Math.max(maxTime, a.completionTime());
}
return maxTime;
}
private void commitTempPlacement() { private void commitTempPlacement() {
for (int i = 0; i < mCountX; i++) { for (int i = 0; i < mCountX; i++) {
for (int j = 0; j < mCountY; j++) { for (int j = 0; j < mCountY; j++) {
+5 -8
View File
@@ -2770,7 +2770,8 @@ public class Workspace extends SmoothPagedView
ItemInfo info = (ItemInfo) d.dragInfo; ItemInfo info = (ItemInfo) d.dragInfo;
mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1], 1, 1, mDragTargetLayout, mTargetCell); (int) mDragViewVisualCenter[1], item.spanX, item.spanY,
mDragTargetLayout, mTargetCell);
setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]); setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
@@ -2790,11 +2791,6 @@ public class Workspace extends SmoothPagedView
minSpanY = item.minSpanY; minSpanY = item.minSpanY;
} }
int[] reorderPosition = new int[2];
reorderPosition = findNearestArea((int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1], item.spanX, item.spanY, mDragTargetLayout,
reorderPosition);
boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int) boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX, mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
item.spanY, child, mTargetCell); item.spanY, child, mTargetCell);
@@ -2805,8 +2801,9 @@ public class Workspace extends SmoothPagedView
mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,
d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion()); d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());
} else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER) } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
&& !mReorderAlarm.alarmPending() && (mLastReorderX != reorderPosition[0] || && !mReorderAlarm.alarmPending() && (mLastReorderX != mTargetCell[0] ||
mLastReorderY != reorderPosition[1])) { mLastReorderY != mTargetCell[1])) {
// Otherwise, if we aren't adding to or creating a folder and there's no pending // Otherwise, if we aren't adding to or creating a folder and there's no pending
// reorder, then we schedule a reorder // reorder, then we schedule a reorder
ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter, ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,