diff options
| author | 2012-09-19 18:13:44 -0700 | |
|---|---|---|
| committer | 2012-09-21 13:48:40 -0700 | |
| commit | 7b7578184567f4e4f0740ce935cc192765410cca (patch) | |
| tree | 481b803ceb22262b36810cac3f31112527eeda12 | |
| parent | 93941683c22d12ad88c0b442f9d00e20a351f15a (diff) | |
Bug #6110465. Optical bounds support for all ViewGroup subclasses.
This CL generalizes the optical bounds support previously contained in the
GridLayout implementation and then incorporates the new form directly into
the base View and ViewGroup implementations. After this change, GridLayout is
returned to an 'optical bounds' unaware state, and all layouts (including non-platform
ones) inherit the ability to perform their layout operation by optical (rather than clip)
bounds using their existing implementations.
The "layoutMode" property of ViewGroup and its associated constants are
made public in this CL.
Change-Id: Ic1bba0e1c6fc14da4aeab0b28c975d562b5f82dd
| -rw-r--r-- | api/current.txt | 4 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 56 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 201 | ||||
| -rw-r--r-- | core/java/android/widget/GridLayout.java | 77 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 33 | ||||
| -rwxr-xr-x | core/res/res/values/attrs.xml | 8 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/Drawable.java | 2 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/DrawableContainer.java | 4 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/NinePatchDrawable.java | 30 | ||||
| -rw-r--r-- | tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java | 5 |
10 files changed, 280 insertions, 140 deletions
diff --git a/api/current.txt b/api/current.txt index 5b126a70d32f..20fdd5cdf334 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25563,6 +25563,7 @@ package android.view { method public android.view.View getFocusedChild(); method public android.view.animation.LayoutAnimationController getLayoutAnimation(); method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener(); + method public int getLayoutMode(); method public android.animation.LayoutTransition getLayoutTransition(); method public int getPersistentDrawingCache(); method public int indexOfChild(android.view.View); @@ -25610,6 +25611,7 @@ package android.view { method public void setDescendantFocusability(int); method public void setLayoutAnimation(android.view.animation.LayoutAnimationController); method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener); + method public void setLayoutMode(int); method public void setLayoutTransition(android.animation.LayoutTransition); method public void setMotionEventSplittingEnabled(boolean); method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener); @@ -25625,6 +25627,8 @@ package android.view { field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000 field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000 field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000 + field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0 + field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1 field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3 field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1 field public static final int PERSISTENT_NO_CACHE = 0; // 0x0 diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 36011ce24203..d96e5ad125d7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13856,6 +13856,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Return true if o is a ViewGroup that is laying out using optical bounds. + * @hide + */ + public static boolean isLayoutModeOptical(Object o) { + return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); + } + + private boolean setOpticalFrame(int left, int top, int right, int bottom) { + Insets parentInsets = mParent instanceof View ? + ((View) mParent).getOpticalInsets() : Insets.NONE; + Insets childInsets = getOpticalInsets(); + return setFrame( + left + parentInsets.left - childInsets.left, + top + parentInsets.top - childInsets.top, + right + parentInsets.left + childInsets.right, + bottom + parentInsets.top + childInsets.bottom); + } + + /** * Assign a size and position to a view and all of its * descendants * @@ -13881,7 +13900,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int oldT = mTop; int oldB = mBottom; int oldR = mRight; - boolean changed = setFrame(l, t, r, b); + boolean changed = isLayoutModeOptical(mParent) ? + setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; @@ -14681,24 +14701,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); } + Insets computeOpticalInsets() { + return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); + } + /** * @hide */ public Insets getOpticalInsets() { if (mLayoutInsets == null) { - mLayoutInsets = (mBackground == null) ? Insets.NONE : mBackground.getLayoutInsets(); + mLayoutInsets = computeOpticalInsets(); } return mLayoutInsets; } /** - * @hide - */ - public void setLayoutInsets(Insets layoutInsets) { - mLayoutInsets = layoutInsets; - } - - /** * Changes the selection state of this view. A view can be selected or not. * Note that selection is not the same as focus. Views are typically * selected in the context of an AdapterView like ListView or GridView; @@ -15372,6 +15389,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #onMeasure(int, int) */ public final void measure(int widthMeasureSpec, int heightMeasureSpec) { + boolean optical = isLayoutModeOptical(this); + if (optical != isLayoutModeOptical(mParent)) { + Insets insets = getOpticalInsets(); + int oWidth = insets.left + insets.right; + int oHeight = insets.top + insets.bottom; + widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); + heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); + } if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec) { @@ -15465,6 +15490,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #MEASURED_STATE_TOO_SMALL}. */ protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { + boolean optical = isLayoutModeOptical(this); + if (optical != isLayoutModeOptical(mParent)) { + Insets insets = getOpticalInsets(); + int opticalWidth = insets.left + insets.right; + int opticalHeight = insets.top + insets.bottom; + + measuredWidth += optical ? opticalWidth : -opticalWidth; + measuredHeight += optical ? opticalHeight : -opticalHeight; + } mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; @@ -17125,6 +17159,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (measureSpec & ~MODE_MASK); } + static int adjust(int measureSpec, int delta) { + return makeMeasureSpec(getSize(measureSpec + delta), getMode(measureSpec)); + } + /** * Returns a String representation of the specified measure * specification. diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index ae10fbebb954..96b2db1d2819 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -23,9 +23,11 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.DashPathEffect; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.PathEffect; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; @@ -83,6 +85,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private static final String TAG = "ViewGroup"; private static final boolean DBG = false; + /** @hide */ + public static boolean DEBUG_DRAW = false; /** * Views which have been hidden or removed which need to be animated on @@ -180,10 +184,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager }) protected int mGroupFlags; - /* - * The layout mode: either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS} + /** + * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}. */ - private int mLayoutMode = CLIP_BOUNDS; + private int mLayoutMode = DEFAULT_LAYOUT_MODE; /** * NOTE: If you change the flags below make sure to reflect the changes @@ -356,20 +360,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * This constant is a {@link #setLayoutMode(int) layoutMode}. * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top}, * {@link #getRight() right} and {@link #getBottom() bottom}. - * - * @hide */ - public static final int CLIP_BOUNDS = 0; + public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; /** * This constant is a {@link #setLayoutMode(int) layoutMode}. * Optical bounds describe where a widget appears to be. They sit inside the clip * bounds which need to cover a larger area to allow other effects, * such as shadows and glows, to be drawn. - * - * @hide */ - public static final int OPTICAL_BOUNDS = 1; + public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; + + /** @hide */ + public static int DEFAULT_LAYOUT_MODE = LAYOUT_MODE_CLIP_BOUNDS; /** * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL @@ -434,7 +437,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } private boolean debugDraw() { - return mAttachInfo != null && mAttachInfo.mDebugLayout; + return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; } private void initViewGroup() { @@ -504,6 +507,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager setLayoutTransition(new LayoutTransition()); } break; + case R.styleable.ViewGroup_layoutMode: + setLayoutMode(a.getInt(attr, DEFAULT_LAYOUT_MODE)); + break; } } @@ -2420,7 +2426,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i = 0; i < count; i++) { final View child = children[i]; child.dispatchAttachedToWindow(info, - visibility | (child.mViewFlags&VISIBILITY_MASK)); + visibility | (child.mViewFlags & VISIBILITY_MASK)); } } @@ -2682,20 +2688,89 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return b; } - private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, int color) { - Paint paint = getDebugPaint(); - paint.setColor(color); + /** Return true if this ViewGroup is laying out using optical bounds. */ + boolean isLayoutModeOptical() { + return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS; + } + + Insets computeOpticalInsets() { + if (isLayoutModeOptical()) { + int left = 0; + int top = 0; + int right = 0; + int bottom = 0; + for (int i = 0; i < mChildrenCount; i++) { + View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + Insets insets = child.getOpticalInsets(); + left = Math.max(left, insets.left); + top = Math.max(top, insets.top); + right = Math.max(right, insets.right); + bottom = Math.max(bottom, insets.bottom); + } + } + return Insets.of(left, top, right, bottom); + } else { + return Insets.NONE; + } + } + + private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) { + if (x1 != x2 && y1 != y2) { + if (x1 > x2) { + int tmp = x1; x1 = x2; x2 = tmp; + } + if (y1 > y2) { + int tmp = y1; y1 = y2; y2 = tmp; + } + canvas.drawRect(x1, y1, x2, y2, paint); + } + } + + private static int sign(int x) { + return (x >= 0) ? 1 : -1; + } - canvas.drawLines(getDebugLines(x1, y1, x2, y2), paint); + private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) { + fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy)); + fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy); + } + + private int dipsToPixels(int dips) { + float scale = getContext().getResources().getDisplayMetrics().density; + return (int) (dips * scale + 0.5f); + } + + private void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint, + int lineLength, int lineWidth) { + drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth); + drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth); + drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth); + drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth); + } + + private static void fillDifference(Canvas canvas, + int x2, int y2, int x3, int y3, + int dx1, int dy1, int dx2, int dy2, Paint paint) { + int x1 = x2 - dx1; + int y1 = y2 - dy1; + + int x4 = x3 + dx2; + int y4 = y3 + dy2; + + fillRect(canvas, paint, x1, y1, x4, y2); + fillRect(canvas, paint, x1, y2, x2, y3); + fillRect(canvas, paint, x3, y2, x4, y3); + fillRect(canvas, paint, x1, y3, x4, y4); } /** * @hide */ - protected void onDebugDrawMargins(Canvas canvas) { + protected void onDebugDrawMargins(Canvas canvas, Paint paint) { for (int i = 0; i < getChildCount(); i++) { View c = getChildAt(i); - c.getLayoutParams().onDebugDraw(c, canvas); + c.getLayoutParams().onDebugDraw(c, canvas, paint); } } @@ -2703,26 +2778,49 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @hide */ protected void onDebugDraw(Canvas canvas) { + Paint paint = getDebugPaint(); + // Draw optical bounds - if (getLayoutMode() == OPTICAL_BOUNDS) { + { + paint.setColor(Color.RED); + paint.setStyle(Paint.Style.STROKE); + PathEffect pathEffect = paint.getPathEffect(); + int len = dipsToPixels(4); + paint.setPathEffect(new DashPathEffect(new float[]{len, len}, 0)); + for (int i = 0; i < getChildCount(); i++) { View c = getChildAt(i); Insets insets = c.getOpticalInsets(); - drawRect(canvas, - c.getLeft() + insets.left, - c.getTop() + insets.top, - c.getRight() - insets.right, - c.getBottom() - insets.bottom, Color.RED); + + drawRect(canvas, paint, + c.getLeft() + insets.left, + c.getTop() + insets.top, + c.getRight() - insets.right - 1, + c.getBottom() - insets.bottom - 1); } + paint.setPathEffect(pathEffect); } // Draw margins - onDebugDrawMargins(canvas); + { + paint.setColor(Color.argb(63, 255, 0, 255)); + paint.setStyle(Paint.Style.FILL); - // Draw bounds - for (int i = 0; i < getChildCount(); i++) { - View c = getChildAt(i); - drawRect(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), Color.BLUE); + onDebugDrawMargins(canvas, paint); + } + + // Draw clip bounds + { + paint.setColor(Color.rgb(63, 127, 255)); + paint.setStyle(Paint.Style.FILL); + + int lineLength = dipsToPixels(8); + int lineWidth = dipsToPixels(1); + for (int i = 0; i < getChildCount(); i++) { + View c = getChildAt(i); + drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), + paint, lineLength, lineWidth); + } } } @@ -4613,13 +4711,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Returns the basis of alignment during layout operations on this view group: - * either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}. + * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}. * * @return the layout mode to use during layout operations * * @see #setLayoutMode(int) - * - * @hide */ public int getLayoutMode() { return mLayoutMode; @@ -4627,15 +4723,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Sets the basis of alignment during the layout of this view group. - * Valid values are either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}. + * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or + * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}. * <p> - * The default is {@link #CLIP_BOUNDS}. + * The default is {@link #LAYOUT_MODE_CLIP_BOUNDS}. * * @param layoutMode the layout mode to use during layout operations * * @see #getLayoutMode() - * - * @hide */ public void setLayoutMode(int layoutMode) { if (mLayoutMode != layoutMode) { @@ -5501,7 +5596,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * * @hide */ - public void onDebugDraw(View view, Canvas canvas) { + public void onDebugDraw(View view, Canvas canvas, Paint paint) { } /** @@ -5846,12 +5941,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @hide */ @Override - public void onDebugDraw(View view, Canvas canvas) { - drawRect(canvas, - view.getLeft() - leftMargin, - view.getTop() - topMargin, - view.getRight() + rightMargin, - view.getBottom() + bottomMargin, Color.MAGENTA); + public void onDebugDraw(View view, Canvas canvas, Paint paint) { + Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE; + + fillDifference(canvas, + view.getLeft() + oi.left, + view.getTop() + oi.top, + view.getRight() - oi.right, + view.getBottom() - oi.bottom, + leftMargin, + topMargin, + rightMargin, + bottomMargin, + paint); } } @@ -6185,14 +6287,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return sDebugPaint; } - private static float[] getDebugLines(int x1, int y1, int x2, int y2) { + private void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) { if (sDebugLines== null) { sDebugLines = new float[16]; } - x2--; - y2--; - sDebugLines[0] = x1; sDebugLines[1] = y1; sDebugLines[2] = x2; @@ -6201,18 +6300,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager sDebugLines[4] = x2; sDebugLines[5] = y1; sDebugLines[6] = x2; - sDebugLines[7] = y2 + 1; + sDebugLines[7] = y2; - sDebugLines[8] = x2 + 1; + sDebugLines[8] = x2; sDebugLines[9] = y2; sDebugLines[10] = x1; sDebugLines[11] = y2; - sDebugLines[12] = x1; - sDebugLines[13] = y2; + sDebugLines[12] = x1; + sDebugLines[13] = y2; sDebugLines[14] = x1; sDebugLines[15] = y1; - return sDebugLines; + canvas.drawLines(sDebugLines, paint); } } diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 772d748bd77f..85ed8dbd4927 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -605,7 +605,7 @@ public class GridLayout extends ViewGroup { } private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { - return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading); + return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading); } private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) { @@ -824,13 +824,11 @@ public class GridLayout extends ViewGroup { // Draw grid private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) { - int dx = getPaddingLeft(); - int dy = getPaddingTop(); if (isLayoutRtl()) { int width = getWidth(); - graphics.drawLine(width - dx - x1, dy + y1, width - dx - x2, dy + y2, paint); + graphics.drawLine(width - x1, y1, width - x2, y2, paint); } else { - graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint); + graphics.drawLine(x1, y1, x2, y2, paint); } } @@ -838,18 +836,17 @@ public class GridLayout extends ViewGroup { * @hide */ @Override - protected void onDebugDrawMargins(Canvas canvas) { + protected void onDebugDrawMargins(Canvas canvas, Paint paint) { // Apply defaults, so as to remove UNDEFINED values LayoutParams lp = new LayoutParams(); for (int i = 0; i < getChildCount(); i++) { View c = getChildAt(i); - Insets insets = getLayoutMode() == OPTICAL_BOUNDS ? c.getOpticalInsets() : Insets.NONE; lp.setMargins( - getMargin1(c, true, true) - insets.left, - getMargin1(c, false, true) - insets.top, - getMargin1(c, true, false) - insets.right, - getMargin1(c, false, false) - insets.bottom); - lp.onDebugDraw(c, canvas); + getMargin1(c, true, true), + getMargin1(c, false, true), + getMargin1(c, true, false), + getMargin1(c, false, false)); + lp.onDebugDraw(c, canvas, paint); } } @@ -858,26 +855,30 @@ public class GridLayout extends ViewGroup { */ @Override protected void onDebugDraw(Canvas canvas) { - int height = getHeight() - getPaddingTop() - getPaddingBottom(); - int width = getWidth() - getPaddingLeft() - getPaddingRight(); - Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.argb(50, 255, 255, 255)); + Insets insets = getOpticalInsets(); + + int top = getPaddingTop() + insets.top; + int left = getPaddingLeft() + insets.left; + int right = getWidth() - getPaddingRight() - insets.right; + int bottom = getHeight() - getPaddingBottom() - insets.bottom; + int[] xs = horizontalAxis.locations; if (xs != null) { for (int i = 0, length = xs.length; i < length; i++) { - int x = xs[i]; - drawLine(canvas, x, 0, x, height - 1, paint); + int x = left + xs[i]; + drawLine(canvas, x, top, x, bottom, paint); } } int[] ys = verticalAxis.locations; if (ys != null) { for (int i = 0, length = ys.length; i < length; i++) { - int y = ys[i]; - drawLine(canvas, 0, y, width - 1, y, paint); + int y = top + ys[i]; + drawLine(canvas, left, y, right, y, paint); } } @@ -1013,12 +1014,7 @@ public class GridLayout extends ViewGroup { } private int getMeasurement(View c, boolean horizontal) { - int result = horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); - if (getLayoutMode() == OPTICAL_BOUNDS) { - Insets insets = c.getOpticalInsets(); - return result - (horizontal ? insets.left + insets.right : insets.top + insets.bottom); - } - return result; + return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); } final int getMeasurementIncludingMargin(View c, boolean horizontal) { @@ -1124,14 +1120,6 @@ public class GridLayout extends ViewGroup { targetWidth - width - paddingRight - rightMargin - dx; int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin; - boolean useLayoutBounds = getLayoutMode() == OPTICAL_BOUNDS; - if (useLayoutBounds) { - Insets insets = c.getOpticalInsets(); - cx -= insets.left; - cy -= insets.top; - width += (insets.left + insets.right); - height += (insets.top + insets.bottom); - } if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) { c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); } @@ -2418,6 +2406,8 @@ public class GridLayout extends ViewGroup { * <li> {@code spec.span = [start, start + size]} </li> * <li> {@code spec.alignment = alignment} </li> * </ul> + * <p> + * To leave the start index undefined, use the value {@link #UNDEFINED}. * * @param start the start * @param size the size @@ -2433,9 +2423,13 @@ public class GridLayout extends ViewGroup { * <li> {@code spec.span = [start, start + 1]} </li> * <li> {@code spec.alignment = alignment} </li> * </ul> + * <p> + * To leave the start index undefined, use the value {@link #UNDEFINED}. * * @param start the start index * @param alignment the alignment + * + * @see #spec(int, int, Alignment) */ public static Spec spec(int start, Alignment alignment) { return spec(start, 1, alignment); @@ -2446,9 +2440,13 @@ public class GridLayout extends ViewGroup { * <ul> * <li> {@code spec.span = [start, start + size]} </li> * </ul> + * <p> + * To leave the start index undefined, use the value {@link #UNDEFINED}. * * @param start the start * @param size the size + * + * @see #spec(int, Alignment) */ public static Spec spec(int start, int size) { return spec(start, size, UNDEFINED_ALIGNMENT); @@ -2459,8 +2457,12 @@ public class GridLayout extends ViewGroup { * <ul> * <li> {@code spec.span = [start, start + 1]} </li> * </ul> + * <p> + * To leave the start index undefined, use the value {@link #UNDEFINED}. * * @param start the start index + * + * @see #spec(int, int) */ public static Spec spec(int start) { return spec(start, 1); @@ -2654,14 +2656,7 @@ public class GridLayout extends ViewGroup { @Override public int getAlignmentValue(View view, int viewSize, int mode) { int baseline = view.getBaseline(); - if (baseline == -1) { - return UNDEFINED; - } else { - if (mode == OPTICAL_BOUNDS) { - return baseline - view.getOpticalInsets().top; - } - return baseline; - } + return baseline == -1 ? UNDEFINED : baseline; } @Override diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index dd2ff3562499..f80a29460da0 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -26,6 +26,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Canvas; +import android.graphics.Insets; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; @@ -4214,6 +4215,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ///////////////////////////////////////////////////////////////////////// + private int getBoxHeight(Layout l) { + Insets opticalInsets = isLayoutModeOptical(mParent) ? getOpticalInsets() : Insets.NONE; + int padding = (l == mHintLayout) ? + getCompoundPaddingTop() + getCompoundPaddingBottom() : + getExtendedPaddingTop() + getExtendedPaddingBottom(); + return getMeasuredHeight() - padding + opticalInsets.top + opticalInsets.bottom; + } + int getVerticalOffset(boolean forceNormal) { int voffset = 0; final int gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; @@ -4224,15 +4233,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (gravity != Gravity.TOP) { - int boxht; - - if (l == mHintLayout) { - boxht = getMeasuredHeight() - getCompoundPaddingTop() - - getCompoundPaddingBottom(); - } else { - boxht = getMeasuredHeight() - getExtendedPaddingTop() - - getExtendedPaddingBottom(); - } + int boxht = getBoxHeight(l); int textht = l.getHeight(); if (textht < boxht) { @@ -4255,15 +4256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (gravity != Gravity.BOTTOM) { - int boxht; - - if (l == mHintLayout) { - boxht = getMeasuredHeight() - getCompoundPaddingTop() - - getCompoundPaddingBottom(); - } else { - boxht = getMeasuredHeight() - getExtendedPaddingTop() - - getExtendedPaddingBottom(); - } + int boxht = getBoxHeight(l); int textht = l.getHeight(); if (textht < boxht) { @@ -4999,6 +4992,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener voffset = getVerticalOffset(true); } + if (isLayoutModeOptical(mParent)) { + voffset -= getOpticalInsets().top; + } + return getExtendedPaddingTop() + voffset + mLayout.getLineBaseline(0); } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 0755038e8ffc..66619fdbf383 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2244,6 +2244,14 @@ See {@link android.view.ViewGroup#setMotionEventSplittingEnabled(boolean)} for more information. --> <attr name="splitMotionEvents" format="boolean" /> + + <!-- Defines the layout mode of this ViewGroup. --> + <attr name="layoutMode"> + <!-- Use the children's clip bounds when laying out this container. --> + <enum name="clipBounds" value="0" /> + <!-- Use the children's optical bounds when laying out this container. --> + <enum name="opticalBounds" value="1" /> + </attr> </declare-styleable> <!-- A {@link android.view.ViewStub} lets you lazily include other XML layouts diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index f9392e462220..54d1bf57fa0c 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -715,7 +715,7 @@ public abstract class Drawable { * * @hide */ - public Insets getLayoutInsets() { + public Insets getOpticalInsets() { return Insets.NONE; } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 41b272df53fc..3af2969faaac 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -95,8 +95,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { * @hide */ @Override - public Insets getLayoutInsets() { - return (mCurrDrawable == null) ? Insets.NONE : mCurrDrawable.getLayoutInsets(); + public Insets getOpticalInsets() { + return (mCurrDrawable == null) ? Insets.NONE : mCurrDrawable.getOpticalInsets(); } @Override diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 2ee623316b9e..a9dc22b34efc 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -56,7 +56,7 @@ public class NinePatchDrawable extends Drawable { private NinePatchState mNinePatchState; private NinePatch mNinePatch; private Rect mPadding; - private Insets mLayoutInsets = Insets.NONE; + private Insets mOpticalInsets = Insets.NONE; private Paint mPaint; private boolean mMutated; @@ -96,8 +96,8 @@ public class NinePatchDrawable extends Drawable { * @hide */ public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, - Rect padding, Rect layoutInsets, String srcName) { - this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, layoutInsets), res); + Rect padding, Rect opticalInsets, String srcName) { + this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets), res); mNinePatchState.mTargetDensity = mTargetDensity; } @@ -195,7 +195,7 @@ public class NinePatchDrawable extends Drawable { if (sdensity == tdensity) { mBitmapWidth = mNinePatch.getWidth(); mBitmapHeight = mNinePatch.getHeight(); - mLayoutInsets = mNinePatchState.mLayoutInsets; + mOpticalInsets = mNinePatchState.mOpticalInsets; } else { mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), sdensity, tdensity); @@ -212,7 +212,7 @@ public class NinePatchDrawable extends Drawable { dest.right = Bitmap.scaleFromDensity(src.right, sdensity, tdensity); dest.bottom = Bitmap.scaleFromDensity(src.bottom, sdensity, tdensity); } - mLayoutInsets = scaleFromDensity(mNinePatchState.mLayoutInsets, sdensity, tdensity); + mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity); } } @@ -236,8 +236,8 @@ public class NinePatchDrawable extends Drawable { * @hide */ @Override - public Insets getLayoutInsets() { - return mLayoutInsets; + public Insets getOpticalInsets() { + return mOpticalInsets; } @Override @@ -299,7 +299,7 @@ public class NinePatchDrawable extends Drawable { options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi; final Rect padding = new Rect(); - final Rect layoutInsets = new Rect(); + final Rect opticalInsets = new Rect(); Bitmap bitmap = null; try { @@ -323,7 +323,7 @@ public class NinePatchDrawable extends Drawable { setNinePatchState(new NinePatchState( new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), - padding, layoutInsets, dither), r); + padding, opticalInsets, dither), r); mNinePatchState.mTargetDensity = mTargetDensity; a.recycle(); @@ -397,7 +397,7 @@ public class NinePatchDrawable extends Drawable { private final static class NinePatchState extends ConstantState { final NinePatch mNinePatch; final Rect mPadding; - final Insets mLayoutInsets; + final Insets mOpticalInsets; final boolean mDither; int mChangingConfigurations; int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; @@ -406,14 +406,14 @@ public class NinePatchDrawable extends Drawable { this(ninePatch, padding, new Rect(), DEFAULT_DITHER); } - NinePatchState(NinePatch ninePatch, Rect padding, Rect layoutInsets) { - this(ninePatch, padding, layoutInsets, DEFAULT_DITHER); + NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets) { + this(ninePatch, padding, opticalInsets, DEFAULT_DITHER); } - NinePatchState(NinePatch ninePatch, Rect rect, Rect layoutInsets, boolean dither) { + NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither) { mNinePatch = ninePatch; mPadding = rect; - mLayoutInsets = Insets.of(layoutInsets); + mOpticalInsets = Insets.of(opticalInsets); mDither = dither; } @@ -423,7 +423,7 @@ public class NinePatchDrawable extends Drawable { mNinePatch = new NinePatch(state.mNinePatch); // Note we don't copy the padding because it is immutable. mPadding = state.mPadding; - mLayoutInsets = state.mLayoutInsets; + mOpticalInsets = state.mOpticalInsets; mDither = state.mDither; mChangingConfigurations = state.mChangingConfigurations; mTargetDensity = state.mTargetDensity; diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java index 103de2f4d28d..81440a5dc9be 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java @@ -10,9 +10,8 @@ import android.widget.Button; import android.widget.GridLayout; import android.widget.TextView; -import static android.widget.GridLayout.ALIGN_BOUNDS; import static android.widget.GridLayout.LayoutParams; -import static android.widget.GridLayout.OPTICAL_BOUNDS; +import static android.widget.GridLayout.LAYOUT_MODE_OPTICAL_BOUNDS; public class LayoutInsetsTest extends Activity { static int[] GRAVITIES = {Gravity.LEFT, Gravity.LEFT, Gravity.CENTER_HORIZONTAL, Gravity.RIGHT, Gravity.RIGHT}; @@ -23,7 +22,7 @@ public class LayoutInsetsTest extends Activity { GridLayout p = new GridLayout(context); p.setUseDefaultMargins(true); //p.setAlignmentMode(ALIGN_BOUNDS); - p.setLayoutMode(OPTICAL_BOUNDS); + p.setLayoutMode(LAYOUT_MODE_OPTICAL_BOUNDS); p.setColumnCount(N); |