From fd2b002bcfca73958233a4e83a737612393e8a16 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Fri, 6 Aug 2010 13:08:56 -0700 Subject: [PATCH] Add 3D rotation to View Change-Id: I4aa2542eb821e82d44e13d69b0938de13ffd4f0d --- api/current.xml | 59 ++++++++++ core/java/android/view/View.java | 155 ++++++++++++++++++++++++-- core/java/android/view/ViewGroup.java | 17 ++- 3 files changed, 211 insertions(+), 20 deletions(-) diff --git a/api/current.xml b/api/current.xml index 3d8375ff30e95..4b94d1c010e70 100644 --- a/api/current.xml +++ b/api/current.xml @@ -193711,6 +193711,28 @@ visibility="public" > + + + + + + + + + + + + + + NONZERO_EPSILON); + } + /** * Recomputes the transform matrix if necessary. * @@ -4896,10 +4951,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if (mMatrixDirty) { // transform-related properties have changed since the last time someone // asked for the matrix; recalculate it with the current values + + // Figure out if we need to update the pivot point + if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) { + if ((mRight - mLeft) != mPrevWidth && (mBottom - mTop) != mPrevHeight) { + mPrevWidth = mRight - mLeft; + mPrevHeight = mBottom - mTop; + mPivotX = (float) mPrevWidth / 2f; + mPivotY = (float) mPrevHeight / 2f; + } + } mMatrix.reset(); mMatrix.setTranslate(mTranslationX, mTranslationY); mMatrix.preRotate(mRotation, mPivotX, mPivotY); mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY); + if (nonzero(mRotationX) || nonzero(mRotationY)) { + if (mCamera == null) { + mCamera = new Camera(); + matrix3D = new Matrix(); + } + mCamera.save(); + mCamera.rotateX(mRotationX); + mCamera.rotateY(mRotationY); + mCamera.getMatrix(matrix3D); + matrix3D.preTranslate(-mPivotX, -mPivotY); + matrix3D.postTranslate(mPivotX, mPivotY); + mMatrix.postConcat(matrix3D); + mCamera.restore(); + } mMatrixDirty = false; mMatrixIsIdentity = mMatrix.isIdentity(); mInverseMatrixDirty = true; @@ -4954,6 +5033,64 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } } + /** + * The degrees that the view is rotated around the vertical axis through the pivot point. + * + * @see #getPivotX() + * @see #getPivotY() + * @return The degrees of Y rotation. + */ + public float getRotationY() { + return mRotationY; + } + + /** + * Sets the degrees that the view is rotated around the vertical axis through pivot point. + * + * @param rotationY The degrees of Y rotation. + * @see #getPivotX() + * @see #getPivotY() + */ + public void setRotationY(float rotationY) { + if (mRotationY != rotationY) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mRotationY = rotationY; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + + /** + * The degrees that the view is rotated around the horizontal axis through the pivot point. + * + * @see #getPivotX() + * @see #getPivotY() + * @return The degrees of X rotation. + */ + public float getRotationX() { + return mRotationX; + } + + /** + * Sets the degrees that the view is rotated around the horizontal axis through pivot point. + * + * @param rotationX The degrees of X rotation. + * @see #getPivotX() + * @see #getPivotY() + */ + public void setRotationX(float rotationX) { + if (mRotationX != rotationX) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mRotationX = rotationX; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + /** * The amount that the view is scaled in x around the pivot point, as a proportion of * the view's unscaled width. A value of 1, the default, means that no scaling is applied. @@ -5035,6 +5172,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility /** * Sets the x location of the point around which the view is * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. + * By default, the pivot point is centered on the object. + * Setting this property disables this behavior and causes the view to use only the + * explicitly set pivotX and pivotY values. * * @param pivotX The x location of the pivot point. * @see #getRotation() @@ -5043,6 +5183,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * @see #getPivotY() */ public void setPivotX(float pivotX) { + mPrivateFlags |= PIVOT_EXPLICITLY_SET; if (mPivotX != pivotX) { // Double-invalidation is necessary to capture view's old and new areas invalidate(); @@ -5069,7 +5210,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility /** * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} - * and {@link #setScaleY(float) scaled}. + * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. + * Setting this property disables this behavior and causes the view to use only the + * explicitly set pivotX and pivotY values. * * @param pivotY The y location of the pivot point. * @see #getRotation() @@ -5078,6 +5221,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * @see #getPivotY() */ public void setPivotY(float pivotY) { + mPrivateFlags |= PIVOT_EXPLICITLY_SET; if (mPivotY != pivotY) { // Double-invalidation is necessary to capture view's old and new areas invalidate(); @@ -5312,15 +5456,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * is still within the view. */ private boolean pointInView(float localX, float localY, float slop) { - if (!hasIdentityMatrix() && mAttachInfo != null) { - // non-identity matrix: transform the point into the view's coordinates - final float[] localXY = mAttachInfo.mTmpTransformLocation; - localXY[0] = localX; - localXY[1] = localY; - getInverseMatrix().mapPoints(localXY); - localX = localXY[0]; - localY = localXY[1]; - } return localX > -slop && localY > -slop && localX < ((mRight - mLeft) + slop) && localY < ((mBottom - mTop) + slop); } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 9da56378684c4..fa86a689a1b44 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -905,19 +905,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } // Calculate the offset point into the target's local coordinates - float xc; - float yc; - if (target.hasIdentityMatrix() || mAttachInfo == null) { - xc = scrolledXFloat - (float) target.mLeft; - yc = scrolledYFloat - (float) target.mTop; - } else { + float xc = scrolledXFloat - (float) target.mLeft; + float yc = scrolledYFloat - (float) target.mTop; + if (!target.hasIdentityMatrix() && mAttachInfo != null) { // non-identity matrix: transform the point into the view's coordinates final float[] localXY = mAttachInfo.mTmpTransformLocation; - localXY[0] = scrolledXFloat; - localXY[1] = scrolledYFloat; + localXY[0] = xc; + localXY[1] = yc; target.getInverseMatrix().mapPoints(localXY); - xc = localXY[0] - (float) target.mLeft; - yc = localXY[1] - (float) target.mTop; + xc = localXY[0]; + yc = localXY[1]; } // if have a target, see if we're allowed to and want to intercept its