diff options
-rw-r--r-- | res/values-xlarge/config.xml | 7 | ||||
-rw-r--r-- | src/com/android/launcher2/CellLayout.java | 100 | ||||
-rw-r--r-- | src/com/android/launcher2/InterruptibleInOutAnimator.java | 69 |
3 files changed, 151 insertions, 25 deletions
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml index f6f66461b..c7c68e22f 100644 --- a/res/values-xlarge/config.xml +++ b/res/values-xlarge/config.xml @@ -38,4 +38,11 @@ the drag view should be offset from the position of the original view. --> <integer name="config_dragViewOffsetX">0</integer> <integer name="config_dragViewOffsetY">12</integer> + + <!-- The duration (in ms) of the fade animation on the object outlines, used when + we are dragging objects around on the home screen. --> + <integer name="config_dragOutlineFadeTime">900</integer> + + <!-- The alpha value at which to show the most recent drop visualization outline. --> + <integer name="config_dragOutlineMaxAlpha">180</integer> </resources> diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 08560e930..0f1d46998 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -31,13 +31,14 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.view.ContextMenu; import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; import android.view.animation.LayoutAnimationController; import java.util.Arrays; @@ -79,15 +80,23 @@ public class CellLayout extends ViewGroup implements Dimmable { private Drawable mBackground; private Drawable mBackgroundMini; private Drawable mBackgroundMiniHover; - // If we're actively dragging something over this screen and it's small, - // mHover is true + // If we're actively dragging something over this screen and it's small, mHover is true private boolean mHover = false; - private final RectF mDragRect = new RectF(); private final Point mDragCenter = new Point(); private Drawable mDragRectDrawable; + // These arrays are used to implement the drag visualization on x-large screens. + // They are used as circular arrays, indexed by mDragRectCurrent. + private Rect[] mDragRects = new Rect[8]; + private int[] mDragRectAlphas = new int[mDragRects.length]; + private InterruptibleInOutAnimator[] mDragRectAnims = + new InterruptibleInOutAnimator[mDragRects.length]; + + // Used as an index into the above 3 arrays; indicates which is the most current value. + private int mDragRectCurrent = 0; + private Drawable mCrosshairsDrawable = null; private ValueAnimator mCrosshairsAnimator = null; private float mCrosshairsVisibility = 0.0f; @@ -139,15 +148,18 @@ public class CellLayout extends ViewGroup implements Dimmable { if (LauncherApplication.isScreenXLarge()) { final Resources res = getResources(); - mBackgroundMini = getResources().getDrawable(R.drawable.mini_home_screen_bg); + mBackgroundMini = res.getDrawable(R.drawable.mini_home_screen_bg); mBackgroundMini.setFilterBitmap(true); - mBackground = getResources().getDrawable(R.drawable.home_screen_bg); + mBackground = res.getDrawable(R.drawable.home_screen_bg); mBackground.setFilterBitmap(true); - mBackgroundMiniHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover); + mBackgroundMiniHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover); mBackgroundMiniHover.setFilterBitmap(true); + // Initialize the data structures used for the drag visualization. + mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green); mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs); + Interpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out // Set up the animation for fading the crosshairs in and out int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime); @@ -158,6 +170,32 @@ public class CellLayout extends ViewGroup implements Dimmable { CellLayout.this.invalidate(); } }); + mCrosshairsAnimator.setInterpolator(interp); + + for (int i = 0; i < mDragRects.length; i++) { + mDragRects[i] = new Rect(); + } + + // When dragging things around the home screens, we show a green outline of + // where the item will land. The outlines gradually fade out, leaving a trail + // behind the drag path. + // Set up all the animations that are used to implement this fading. + final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); + final int fromAlphaValue = 0; + final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha); + for (int i = 0; i < mDragRectAnims.length; i++) { + final InterruptibleInOutAnimator anim = + new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); + anim.setInterpolator(interp); + final int thisIndex = i; + anim.addUpdateListener(new AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue(); + CellLayout.this.invalidate(mDragRects[thisIndex]); + } + }); + mDragRectAnims[i] = anim; + } } } @@ -200,16 +238,6 @@ public class CellLayout extends ViewGroup implements Dimmable { final int countX = mCountX; final int countY = mCountY; - if (!mDragRect.isEmpty()) { - mDragRectDrawable.setBounds( - (int)mDragRect.left, - (int)mDragRect.top, - (int)mDragRect.right, - (int)mDragRect.bottom); - mDragRectDrawable.setAlpha((int) (mCrosshairsVisibility * 255)); - mDragRectDrawable.draw(canvas); - } - final float MAX_ALPHA = 0.4f; final int MAX_VISIBLE_DISTANCE = 600; final float DISTANCE_MULTIPLIER = 0.002f; @@ -236,6 +264,15 @@ public class CellLayout extends ViewGroup implements Dimmable { } x += mCellWidth + mWidthGap; } + + for (int i = 0; i < mDragRects.length; i++) { + int alpha = mDragRectAlphas[i]; + if (alpha > 0) { + mDragRectDrawable.setAlpha(alpha); + mDragRectDrawable.setBounds(mDragRects[i]); + mDragRectDrawable.draw(canvas); + } + } } } @@ -751,13 +788,23 @@ public class CellLayout extends ViewGroup implements Dimmable { final int left = topLeft[0]; final int top = topLeft[1]; - // Now find the bottom right - final int[] bottomRight = mTmpPoint; - cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight); - bottomRight[0] += mCellWidth; - bottomRight[1] += mCellHeight; - mDragRect.set(left, top, bottomRight[0], bottomRight[1]); - invalidate(); + final Rect dragRect = mDragRects[mDragRectCurrent]; + + if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) { + // Now find the bottom right + final int[] bottomRight = mTmpPoint; + cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight); + bottomRight[0] += mCellWidth; + bottomRight[1] += mCellHeight; + + final int oldIndex = mDragRectCurrent; + mDragRectCurrent = (oldIndex + 1) % mDragRects.length; + + mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]); + + mDragRectAnims[oldIndex].animateOut(); + mDragRectAnims[mDragRectCurrent].animateIn(); + } } } @@ -973,6 +1020,10 @@ public class CellLayout extends ViewGroup implements Dimmable { if (mCrosshairsAnimator != null) { animateCrosshairsTo(0.0f); } + + mDragRectAnims[mDragRectCurrent].animateOut(); + mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length; + mDragRects[mDragRectCurrent].setEmpty(); } /** @@ -1015,7 +1066,6 @@ public class CellLayout extends ViewGroup implements Dimmable { * or it may have begun on another layout. */ void onDragEnter(View dragView) { - mDragRect.setEmpty(); // Fade in the drag indicators if (mCrosshairsAnimator != null) { animateCrosshairsTo(1.0f); diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java new file mode 100644 index 000000000..fb0728480 --- /dev/null +++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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 com.android.launcher2; + +import android.animation.ValueAnimator; +import android.util.Log; + +/** + * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation. + * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get + * a frame-by-frame mirror of the 'in' animation -- i.e., the interpolated values will + * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the + * interpolator in the same direction. + */ +public class InterruptibleInOutAnimator extends ValueAnimator { + private long mOriginalDuration; + private Object mOriginalFromValue; + private Object mOriginalToValue; + + public InterruptibleInOutAnimator(long duration, Object fromValue, Object toValue) { + super(duration, fromValue, toValue); + mOriginalDuration = duration; + mOriginalFromValue = fromValue; + mOriginalToValue = toValue; + } + + private void animate(Object fromValue, Object toValue) { + // This only makes sense when it's running in the opposite direction, or stopped. + setDuration(mOriginalDuration - getCurrentPlayTime()); + + final Object startValue = isRunning() ? getAnimatedValue() : fromValue; + cancel(); + setValues(startValue, toValue); + start(); + } + + /** + * This is the equivalent of calling Animator.start(), except that it can be called when + * the animation is running in the opposite direction, in which case we reverse + * direction and animate for a correspondingly shorter duration. + */ + public void animateIn() { + animate(mOriginalFromValue, mOriginalToValue); + } + + /** + * This is the roughly the equivalent of calling Animator.reverse(), except that it uses the + * same interpolation curve as animateIn(), rather than mirroring it. Also, like animateIn(), + * if the animation is currently running in the opposite direction, we reverse + * direction and animate for a correspondingly shorter duration. + */ + public void animateOut() { + animate(mOriginalToValue, mOriginalFromValue); + } +} |