diff options
author | Adam Cohen <adamcohen@google.com> | 2011-07-02 18:03:00 -0700 |
---|---|---|
committer | Adam Cohen <adamcohen@google.com> | 2011-07-02 18:42:25 -0700 |
commit | 3e8f811f31a2275e778244427271f77f4116c08b (patch) | |
tree | 53a8530718c95bee2830ca80863bff60f4d1fbf2 | |
parent | 04dc2bc6139ff414e49fc423d28edbd5801cdc03 (diff) | |
download | packages_apps_Trebuchet-3e8f811f31a2275e778244427271f77f4116c08b.tar.gz packages_apps_Trebuchet-3e8f811f31a2275e778244427271f77f4116c08b.tar.bz2 packages_apps_Trebuchet-3e8f811f31a2275e778244427271f77f4116c08b.zip |
Added transitions when dropping items onto Folders, fixed bugs
-> Changed the ordering of the FolderIcon preview to show first items first
-> Folder now closes immediately upon drop of an item from folder to workspace
Change-Id: I66361b604dc5ef81da2413b7dda53d0c4691377e
-rw-r--r-- | res/drawable-hdpi/portal_container_holo.9.png | bin | 10516 -> 9722 bytes | |||
-rw-r--r-- | res/drawable-mdpi/portal_container_holo.9.png | bin | 5894 -> 5392 bytes | |||
-rw-r--r-- | res/values/config.xml | 2 | ||||
-rw-r--r-- | src/com/android/launcher2/DragLayer.java | 112 | ||||
-rw-r--r-- | src/com/android/launcher2/DragView.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher2/Folder.java | 48 | ||||
-rw-r--r-- | src/com/android/launcher2/FolderIcon.java | 33 | ||||
-rw-r--r-- | src/com/android/launcher2/Workspace.java | 23 |
8 files changed, 149 insertions, 85 deletions
diff --git a/res/drawable-hdpi/portal_container_holo.9.png b/res/drawable-hdpi/portal_container_holo.9.png Binary files differindex e2a1bd55e..ab846f66e 100644 --- a/res/drawable-hdpi/portal_container_holo.9.png +++ b/res/drawable-hdpi/portal_container_holo.9.png diff --git a/res/drawable-mdpi/portal_container_holo.9.png b/res/drawable-mdpi/portal_container_holo.9.png Binary files differindex 7eef5d7c5..56a5b8754 100644 --- a/res/drawable-mdpi/portal_container_holo.9.png +++ b/res/drawable-mdpi/portal_container_holo.9.png diff --git a/res/values/config.xml b/res/values/config.xml index 70ee42361..5b7376912 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -67,7 +67,7 @@ <integer name="config_dropAnimMaxDuration">400</integer> <!-- The duration of the UserFolder opening and closing animation --> - <integer name="config_folderAnimDuration">100</integer> + <integer name="config_folderAnimDuration">120</integer> <!-- The distance at which the animation should take the max duration --> <integer name="config_dropAnimMaxDist">800</integer> diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index 0ce153e70..d76b902da 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -32,6 +32,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewParent; import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; @@ -57,8 +59,10 @@ public class DragLayer extends FrameLayout { // Variables relating to animation of views after drop private ValueAnimator mDropAnim = null; private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f); - private int[] mDropViewPos = new int[] { -1, -1 }; private View mDropView = null; + private int[] mDropViewPos = new int[2]; + private float mDropViewScale; + private float mDropViewAlpha; /** * Used to create a new DragLayer from XML. @@ -181,17 +185,19 @@ public class DragLayer extends FrameLayout { } } - public void getViewLocationRelativeToSelf(View v, int[] location) { - getLocationOnScreen(location); - int x = location[0]; - int y = location[1]; + public void getViewRectRelativeToSelf(View v, Rect r) { + int[] loc = new int[2]; + getLocationOnScreen(loc); + int x = loc[0]; + int y = loc[1]; - v.getLocationOnScreen(location); - int vX = location[0]; - int vY = location[1]; + v.getLocationOnScreen(loc); + int vX = loc[0]; + int vY = loc[1]; - location[0] = vX - x; - location[1] = vY - y; + int left = vX - x; + int top = vY - y; + r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight()); } @Override @@ -308,55 +314,59 @@ public class DragLayer extends FrameLayout { ((CellLayoutChildren) child.getParent()).measureChild(child); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - int[] loc = new int[2]; - getViewLocationRelativeToSelf(dragView, loc); + Rect r = new Rect(); + getViewRectRelativeToSelf(dragView, r); int coord[] = new int[2]; coord[0] = lp.x; coord[1] = lp.y; getDescendantCoordRelativeToSelf(child, coord); - final int fromX = loc[0] + (dragView.getWidth() - child.getMeasuredWidth()) / 2; - final int fromY = loc[1] + (dragView.getHeight() - child.getMeasuredHeight()) / 2; - final int dx = coord[0] - fromX; - final int dy = coord[1] - fromY; - + final int fromX = r.left + (dragView.getWidth() - child.getMeasuredWidth()) / 2; + final int fromY = r.top + (dragView.getHeight() - child.getMeasuredHeight()) / 2; child.setVisibility(INVISIBLE); - animateViewIntoPosition(child, fromX, fromY, dx, dy); + animateViewIntoPosition(child, fromX, fromY, coord[0], coord[1]); } private void animateViewIntoPosition(final View view, final int fromX, final int fromY, - final int dX, final int dY) { + final int toX, final int toY) { + Rect from = new Rect(fromX, fromY, fromX + view.getMeasuredWidth(), fromY + view.getMeasuredHeight()); + Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight()); + animateView(view, from, to, 1f, -1); + } + public void animateView(final View view, final Rect from, final Rect to, + final float finalAlpha, int duration) { + animateView(view, from, to, finalAlpha, 1.0f, duration, null, null); + } + + public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha, + final float finalScale, int duration, final Interpolator motionInterpolator, + final Interpolator alphaInterpolator) { // Calculate the duration of the animation based on the object's distance - final float dist = (float) Math.sqrt(dX*dX + dY*dY); + final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) + + Math.pow(to.top - from.top, 2)); final Resources res = getResources(); final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist); - int duration = res.getInteger(R.integer.config_dropAnimMaxDuration); - if (dist < maxDist) { - duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist); + + // If duration < 0, this is a cue to compute the duration based on the distance + if (duration < 0) { + duration = res.getInteger(R.integer.config_dropAnimMaxDuration); + if (dist < maxDist) { + duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist); + } } if (mDropAnim != null) { mDropAnim.end(); } - mDropAnim = new ValueAnimator(); - mDropAnim.setInterpolator(mQuintEaseOutInterpolator); - - // The view is invisible during the animation; we render it manually. - mDropAnim.addListener(new AnimatorListenerAdapter() { - public void onAnimationStart(Animator animation) { - // Set this here so that we don't render it until the animation begins - mDropView = view; - } - public void onAnimationEnd(Animator animation) { - if (mDropView != null) { - mDropView.setVisibility(View.VISIBLE); - mDropView = null; - } - } - }); + mDropView = view; + final float initialAlpha = view.getAlpha(); + mDropAnim = new ValueAnimator(); + if (alphaInterpolator == null || motionInterpolator == null) { + mDropAnim.setInterpolator(mQuintEaseOutInterpolator); + } mDropAnim.setDuration(duration); mDropAnim.setFloatValues(0.0f, 1.0f); @@ -370,12 +380,27 @@ public class DragLayer extends FrameLayout { invalidate(mDropViewPos[0], mDropViewPos[1], mDropViewPos[0] + width, mDropViewPos[1] + height); - mDropViewPos[0] = fromX + (int) (percent * dX + 0.5f); - mDropViewPos[1] = fromY + (int) (percent * dY + 0.5f); + float alphaPercent = alphaInterpolator == null ? percent : + alphaInterpolator.getInterpolation(percent); + float motionPercent = motionInterpolator == null ? percent : + motionInterpolator.getInterpolation(percent); + + mDropViewPos[0] = from.left + (int) ((to.left - from.left) * motionPercent); + mDropViewPos[1] = from.top + (int) ((to.top - from.top) * motionPercent); + mDropViewScale = percent * finalScale + (1 - percent); + mDropViewAlpha = alphaPercent * finalAlpha + (1 - alphaPercent) * initialAlpha; invalidate(mDropViewPos[0], mDropViewPos[1], mDropViewPos[0] + width, mDropViewPos[1] + height); } }); + mDropAnim.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + if (mDropView != null) { + mDropView.setVisibility(View.VISIBLE); + mDropView = null; + } + } + }); mDropAnim.start(); } @@ -388,7 +413,12 @@ public class DragLayer extends FrameLayout { canvas.save(Canvas.MATRIX_SAVE_FLAG); final int xPos = mDropViewPos[0] - mDropView.getScrollX(); final int yPos = mDropViewPos[1] - mDropView.getScrollY(); + int width = mDropView.getMeasuredWidth(); + int height = mDropView.getMeasuredHeight(); canvas.translate(xPos, yPos); + canvas.translate((1 - mDropViewScale) * width / 2, (1 - mDropViewScale) * height / 2); + canvas.scale(mDropViewScale, mDropViewScale); + mDropView.setAlpha(mDropViewAlpha); mDropView.draw(canvas); canvas.restore(); } diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java index 4cc2c5543..d4dc785f7 100644 --- a/src/com/android/launcher2/DragView.java +++ b/src/com/android/launcher2/DragView.java @@ -195,6 +195,16 @@ public class DragView extends View { invalidate(); } + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + if (mPaint == null) { + mPaint = new Paint(); + } + mPaint.setAlpha((int) (255 * alpha)); + invalidate(); + } + /** * Create a window containing this view and show it. * @@ -242,7 +252,11 @@ public class DragView extends View { } void remove() { - mWindowManager.removeView(this); + post(new Runnable() { + public void run() { + mWindowManager.removeView(DragView.this); + } + }); } int[] getPosition(int[] result) { diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index 37368b98e..13815adbc 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -86,6 +86,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL private int mMaxCountX; private int mMaxCountY; private Rect mNewSize = new Rect(); + private Rect mIconRect = new Rect(); private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>(); private Drawable mIconDrawable; boolean mItemsInvalidated = false; @@ -134,6 +135,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL if (sHintText == null) { sHintText = res.getString(R.string.folder_hint_text); } + setLayerType(LAYER_TYPE_HARDWARE, null); } @Override @@ -141,7 +143,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL super.onFinishInflate(); mContent = (CellLayout) findViewById(R.id.folder_content); mContent.setGridSize(0, 0); - mContent.enableHardwareLayers(); mFolderName = (TextView) findViewById(R.id.folder_name); // We find out how tall the text view wants to be (it is set to wrap_content), so that @@ -372,9 +373,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL * to its associated FolderIcon. This allows for a seamless transition into the expanded state. */ private void positionAndSizeAsIcon() { - if (!(getParent() instanceof CellLayoutChildren)) return; + if (!(getParent() instanceof DragLayer)) return; - DragLayer.LayoutParams iconLp = (DragLayer.LayoutParams) mFolderIcon.getLayoutParams(); DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); if (mMode == PARTIAL_GROW) { @@ -382,19 +382,19 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL setScaleY(0.8f); setAlpha(0f); } else { - lp.width = iconLp.width; - lp.height = iconLp.height; - lp.x = iconLp.x; - lp.y = iconLp.y; + mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mFolderIcon, mIconRect); + lp.width = mIconRect.width(); + lp.height = mIconRect.height(); + lp.x = mIconRect.left; + lp.y = mIconRect.top; mContent.setAlpha(0); } mState = STATE_SMALL; } public void animateOpen() { - if (mState != STATE_SMALL) { - positionAndSizeAsIcon(); - } + positionAndSizeAsIcon(); + if (!(getParent() instanceof DragLayer)) return; ObjectAnimator oa; @@ -449,13 +449,12 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f); oa = ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); } else { - DragLayer.LayoutParams iconLp = (DragLayer.LayoutParams) mFolderIcon.getLayoutParams(); DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); - PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", iconLp.width); - PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", iconLp.height); - PropertyValuesHolder x = PropertyValuesHolder.ofInt("x",iconLp.x); - PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", iconLp.y); + PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", mIconRect.width()); + PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", mIconRect.height()); + PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", mIconRect.left); + PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", mIconRect.top); oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y); oa.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { @@ -645,14 +644,18 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() { public void onAlarm(Alarm alarm) { - mLauncher.closeFolder(); - mCurrentDragInfo = null; - mCurrentDragView = null; - mSuppressOnAdd = false; - mRearrangeOnClose = true; + completeDragExit(); } }; + private void completeDragExit() { + mLauncher.closeFolder(); + mCurrentDragInfo = null; + mCurrentDragView = null; + mSuppressOnAdd = false; + mRearrangeOnClose = true; + } + public void onDragExit(DragObject d) { // We only close the folder if this is a true drag exit, ie. not because a drop // has occurred above the folder. @@ -674,6 +677,11 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL } } // TODO: if the drag fails, we need to re-add the item + } else { + if (target != this) { + mOnExitAlarm.cancelAlarm(); + completeDragExit(); + } } } diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java index bae2fd77c..aff8761fd 100644 --- a/src/com/android/launcher2/FolderIcon.java +++ b/src/com/android/launcher2/FolderIcon.java @@ -25,11 +25,14 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -276,17 +279,30 @@ public class FolderIcon extends LinearLayout implements FolderListener { mFolderRingAnimator.animateToNaturalState(); } - public void onDrop(Object dragInfo) { + public void onDrop(DragObject d) { ShortcutInfo item; - if (dragInfo instanceof ApplicationInfo) { + if (d.dragInfo instanceof ApplicationInfo) { // Came from all apps -- make a copy - item = ((ApplicationInfo) dragInfo).makeShortcut(); + item = ((ApplicationInfo) d.dragInfo).makeShortcut(); } else { - item = (ShortcutInfo) dragInfo; + item = (ShortcutInfo) d.dragInfo; } item.cellX = -1; item.cellY = -1; addItem(item); + DragLayer dragLayer = mLauncher.getDragLayer(); + Rect from = new Rect(); + dragLayer.getViewRectRelativeToSelf(d.dragView, from); + Rect to = new Rect(); + dragLayer.getDescendantRectRelativeToSelf(this, to); + + int previewSize = FolderRingAnimator.sPreviewSize; + int vanishingPointX = (int) (previewSize * 0.7); + int vanishingPointY = (int) (previewSize * (1 - 0.88f)); + to.offset(vanishingPointX - previewSize / 2 , vanishingPointY - previewSize / 2); + + dragLayer.animateView(d.dragView, from, to, 0f, 0.2f, 400, new DecelerateInterpolator(2), + new AccelerateInterpolator(2)); } public DropTarget getDropTargetDelegate(DragObject d) { @@ -323,20 +339,17 @@ public class FolderIcon extends LinearLayout implements FolderListener { float maxPerspectiveShift = baselineSize * PERSPECTIVE_SHIFT_FACTOR; ArrayList<View> items = mFolder.getItemsInReadingOrder(false); - int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW); int xShift = (mOriginalWidth - 2 * halfAvailableSpace) / 2; int yShift = previewPadding; canvas.translate(xShift, yShift); - for (int i = firstItemIndex; i < items.size(); i++) { - int index = i - firstItemIndex; - index += Math.max(0, NUM_ITEMS_IN_PREVIEW - items.size()); + int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW); + for (int i = nItemsInPreview - 1; i >= 0; i--) { + int index = NUM_ITEMS_IN_PREVIEW - i - 1; float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1); float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r)); - //r = (float) Math.pow(r, 2); - float offset = (1 - r) * maxPerspectiveShift; float scaledSize = scale * baselineSize; float scaleOffsetCorrection = (1 - scale) * baselineSize; diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 5ba9fd7af..d728001ea 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -2240,12 +2240,12 @@ public class Workspace extends SmoothPagedView } boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell, - Object dragInfo, boolean external) { + DragObject d, boolean external) { View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); if (dropOverView instanceof FolderIcon) { FolderIcon fi = (FolderIcon) dropOverView; - if (fi.acceptDrop(dragInfo)) { - fi.onDrop(dragInfo); + if (fi.acceptDrop(d.dragInfo)) { + fi.onDrop(d); // if the drag started here, we need to remove it from the workspace if (!external) { @@ -2281,7 +2281,7 @@ public class Workspace extends SmoothPagedView if (d.dragSource != this) { final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1] }; - onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d.dragView); + onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d); } else if (mDragInfo != null) { final View cell = mDragInfo.cell; @@ -2305,8 +2305,7 @@ public class Workspace extends SmoothPagedView return; } - if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, - d.dragInfo, false)) { + if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, d, false)) { return; } @@ -2936,7 +2935,7 @@ public class Workspace extends SmoothPagedView * to add an item to one of the workspace screens. */ private void onDropExternal(int[] touchXY, Object dragInfo, - CellLayout cellLayout, boolean insertAtFirst, DragView dragView) { + CellLayout cellLayout, boolean insertAtFirst, DragObject d) { int screen = indexOfChild(cellLayout); if (screen != mCurrentPage && mShrinkState != ShrinkState.SPRING_LOADED) { snapToPage(screen); @@ -2989,7 +2988,7 @@ public class Workspace extends SmoothPagedView if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true)) { return; } - if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, dragInfo, true)) { + if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, d, true)) { return; } } @@ -3008,13 +3007,13 @@ public class Workspace extends SmoothPagedView CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); cellLayout.getChildrenLayout().measureChild(view); - if (dragView != null) { - mLauncher.getDragLayer().animateViewIntoPosition(dragView, view); - } - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, lp.cellX, lp.cellY); + + if (d.dragView != null) { + mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view); + } } } |