summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alan Viverette <alanv@google.com> 2015-04-21 13:00:33 -0700
committer Alan Viverette <alanv@google.com> 2015-04-21 13:00:33 -0700
commit388cd3b69c51a449b8bbb8086dbc429f24783ad1 (patch)
tree380b1e282106043b970a52b34e95e7596bd81580
parent6a1c23bf190db7bfc8bba1973c5a03a5af897623 (diff)
Fix visual styling for Material Spinner background
Adds explicit padding attributes to LayerDrawable, constrains the ripple to fit within the container to avoid projection. Bug: 19359934 Bug: 20083467 Change-Id: I46da941fba37552adeb2c1fe617b799f576df0c6
-rw-r--r--api/current.txt8
-rw-r--r--api/system-current.txt8
-rw-r--r--core/res/res/drawable/ic_spinner_caret.xml26
-rw-r--r--core/res/res/drawable/spinner_background_material.xml35
-rw-r--r--core/res/res/values/attrs.xml14
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java272
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java20
7 files changed, 346 insertions, 37 deletions
diff --git a/api/current.txt b/api/current.txt
index 9a4e905ffe61..23dc128cccc1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12408,7 +12408,9 @@ package android.graphics.drawable {
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
method public int findIndexByLayerId(int);
+ method public int getBottomPadding();
method public android.graphics.drawable.Drawable getDrawable(int);
+ method public int getEndPadding();
method public int getId(int);
method public int getLayerGravity(int);
method public int getLayerHeight(int);
@@ -12419,9 +12421,13 @@ package android.graphics.drawable {
method public int getLayerInsetStart(int);
method public int getLayerInsetTop(int);
method public int getLayerWidth(int);
+ method public int getLeftPadding();
method public int getNumberOfLayers();
method public int getOpacity();
method public int getPaddingMode();
+ method public int getRightPadding();
+ method public int getStartPadding();
+ method public int getTopPadding();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
method public void setAlpha(int);
@@ -12442,7 +12448,9 @@ package android.graphics.drawable {
method public void setLayerSize(int, int, int);
method public void setLayerWidth(int, int);
method public void setOpacity(int);
+ method public void setPadding(int, int, int, int);
method public void setPaddingMode(int);
+ method public void setPaddingRelative(int, int, int, int);
method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
field public static final int PADDING_MODE_NEST = 0; // 0x0
field public static final int PADDING_MODE_STACK = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index 8cdf938a8f8d..92000c857a3b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12702,7 +12702,9 @@ package android.graphics.drawable {
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
method public int findIndexByLayerId(int);
+ method public int getBottomPadding();
method public android.graphics.drawable.Drawable getDrawable(int);
+ method public int getEndPadding();
method public int getId(int);
method public int getLayerGravity(int);
method public int getLayerHeight(int);
@@ -12713,9 +12715,13 @@ package android.graphics.drawable {
method public int getLayerInsetStart(int);
method public int getLayerInsetTop(int);
method public int getLayerWidth(int);
+ method public int getLeftPadding();
method public int getNumberOfLayers();
method public int getOpacity();
method public int getPaddingMode();
+ method public int getRightPadding();
+ method public int getStartPadding();
+ method public int getTopPadding();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
method public void setAlpha(int);
@@ -12736,7 +12742,9 @@ package android.graphics.drawable {
method public void setLayerSize(int, int, int);
method public void setLayerWidth(int, int);
method public void setOpacity(int);
+ method public void setPadding(int, int, int, int);
method public void setPaddingMode(int);
+ method public void setPaddingRelative(int, int, int, int);
method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
field public static final int PADDING_MODE_NEST = 0; // 0x0
field public static final int PADDING_MODE_STACK = 1; // 0x1
diff --git a/core/res/res/drawable/ic_spinner_caret.xml b/core/res/res/drawable/ic_spinner_caret.xml
new file mode 100644
index 000000000000..6a18f8984951
--- /dev/null
+++ b/core/res/res/drawable/ic_spinner_caret.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:pathData="M7,10l5,5,5-5z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml
index d5b509f7052c..892dbc5eb4c3 100644
--- a/core/res/res/drawable/spinner_background_material.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -15,21 +15,24 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
- android:paddingMode="stack">
- <item android:drawable="@drawable/item_background_borderless_material"
- android:gravity="end|center_vertical"
- android:width="24dp"
- android:height="24dp" />
- <item android:gravity="end|center_vertical">
- <vector android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?attr/colorControlNormal">
- <path android:pathData="M7,10l5,5,5-5z"
- android:fillColor="@color/white"/>
- </vector>
+ android:paddingMode="stack"
+ android:paddingStart="0dp"
+ android:paddingEnd="48dp"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+ <item
+ android:gravity="end|center_vertical"
+ android:width="48dp"
+ android:height="48dp">
+ <ripple
+ android:color="?attr/colorControlHighlight"
+ android:radius="24dp" />
</item>
- <item android:end="48dp"
- android:drawable="@color/transparent" />
+
+ <item
+ android:drawable="@drawable/ic_spinner_caret"
+ android:gravity="end|center_vertical"
+ android:width="24dp"
+ android:height="24dp"
+ android:end="12dp" />
</layer-list>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 674c695a6776..a7c4800f504f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5169,6 +5169,20 @@
<!-- Stack each layer directly atop the previous layer. -->
<enum name="stack" value="1" />
</attr>
+ <!-- Explicit top padding. Overrides child padding. -->
+ <attr name="paddingTop" />
+ <!-- Explicit bottom padding. Overrides child padding. -->
+ <attr name="paddingBottom" />
+ <!-- Explicit left padding. Overrides child padding. -->
+ <attr name="paddingLeft" />
+ <!-- Explicit right padding. Overrides child padding. -->
+ <attr name="paddingRight" />
+ <!-- Explicit start padding. Overrides child padding. Takes precedence
+ over absolute padding (e.g. left when layout direction is LTR). -->
+ <attr name="paddingStart" />
+ <!-- Explicit end padding. Overrides child padding. Takes precedence
+ over absolute padding (e.g. right when layout direction is LTR). -->
+ <attr name="paddingEnd" />
</declare-styleable>
<!-- Describes an item (or child) of a LayerDrawable. -->
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 8468d9ed138f..3bbbc7182cdc 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -86,7 +86,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
LayerState mLayerState;
- private int mOpacityOverride = PixelFormat.UNKNOWN;
private int[] mPaddingL;
private int[] mPaddingT;
private int[] mPaddingR;
@@ -177,12 +176,39 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
// Extract the theme attributes, if any.
state.mThemeAttrs = a.extractThemeAttrs();
- mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, mOpacityOverride);
-
- state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored,
- state.mAutoMirrored);
- state.mPaddingMode = a.getInteger(R.styleable.LayerDrawable_paddingMode,
- state.mPaddingMode);
+ final int N = a.getIndexCount();
+ for (int i = 0; i < N; i++) {
+ int attr = a.getIndex(i);
+ switch (attr) {
+ case R.styleable.LayerDrawable_opacity:
+ state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride);
+ break;
+ case R.styleable.LayerDrawable_paddingTop:
+ state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop);
+ break;
+ case R.styleable.LayerDrawable_paddingBottom:
+ state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom);
+ break;
+ case R.styleable.LayerDrawable_paddingLeft:
+ state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft);
+ break;
+ case R.styleable.LayerDrawable_paddingRight:
+ state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight);
+ break;
+ case R.styleable.LayerDrawable_paddingStart:
+ state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart);
+ break;
+ case R.styleable.LayerDrawable_paddingEnd:
+ state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd);
+ break;
+ case R.styleable.LayerDrawable_autoMirrored:
+ state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored);
+ break;
+ case R.styleable.LayerDrawable_paddingMode:
+ state.mPaddingMode = a.getInteger(attr, state.mPaddingMode);
+ break;
+ }
+ }
}
/**
@@ -895,15 +921,210 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public boolean getPadding(Rect padding) {
- if (mLayerState.mPaddingMode == PADDING_MODE_NEST) {
+ final LayerState layerState = mLayerState;
+ if (layerState.mPaddingMode == PADDING_MODE_NEST) {
computeNestedPadding(padding);
} else {
computeStackedPadding(padding);
}
+ // If padding was explicitly specified (e.g. not -1) then override the
+ // computed padding in that dimension.
+ if (layerState.mPaddingTop >= 0) {
+ padding.top = layerState.mPaddingTop;
+ }
+
+ if (layerState.mPaddingBottom >= 0) {
+ padding.bottom = layerState.mPaddingBottom;
+ }
+
+ final int paddingRtlLeft;
+ final int paddingRtlRight;
+ if (getLayoutDirection() == LayoutDirection.RTL) {
+ paddingRtlLeft = layerState.mPaddingEnd;
+ paddingRtlRight = layerState.mPaddingStart;
+ } else {
+ paddingRtlLeft = layerState.mPaddingStart;
+ paddingRtlRight = layerState.mPaddingEnd;
+ }
+
+ final int paddingLeft = paddingRtlLeft >= 0 ? paddingRtlLeft : layerState.mPaddingLeft;
+ if (paddingLeft >= 0) {
+ padding.left = paddingLeft;
+ }
+
+ final int paddingRight = paddingRtlRight >= 0 ? paddingRtlRight : layerState.mPaddingRight;
+ if (paddingRight >= 0) {
+ padding.right = paddingRight;
+ }
+
return padding.left != 0 || padding.top != 0 || padding.right != 0 || padding.bottom != 0;
}
+ /**
+ * Sets the absolute padding.
+ * <p>
+ * If padding in a dimension is specified as {@code -1}, the resolved
+ * padding will use the value computed according to the padding mode (see
+ * {@link #setPaddingMode(int)}).
+ * <p>
+ * Calling this method clears any relative padding values previously set
+ * using {@link #setPaddingRelative(int, int, int, int)}.
+ *
+ * @param left the left padding in pixels, or -1 to use computed padding
+ * @param top the top padding in pixels, or -1 to use computed padding
+ * @param right the right padding in pixels, or -1 to use computed padding
+ * @param bottom the bottom padding in pixels, or -1 to use computed
+ * padding
+ * @attr ref android.R.styleable#LayerDrawable_paddingLeft
+ * @attr ref android.R.styleable#LayerDrawable_paddingTop
+ * @attr ref android.R.styleable#LayerDrawable_paddingRight
+ * @attr ref android.R.styleable#LayerDrawable_paddingBottom
+ * @see #setPaddingRelative(int, int, int, int)
+ */
+ public void setPadding(int left, int top, int right, int bottom) {
+ final LayerState layerState = mLayerState;
+ layerState.mPaddingLeft = left;
+ layerState.mPaddingTop = top;
+ layerState.mPaddingRight = right;
+ layerState.mPaddingBottom = bottom;
+
+ // Clear relative padding values.
+ layerState.mPaddingStart = -1;
+ layerState.mPaddingEnd = -1;
+ }
+
+ /**
+ * Sets the relative padding.
+ * <p>
+ * If padding in a dimension is specified as {@code -1}, the resolved
+ * padding will use the value computed according to the padding mode (see
+ * {@link #setPaddingMode(int)}).
+ * <p>
+ * Calling this method clears any absolute padding values previously set
+ * using {@link #setPadding(int, int, int, int)}.
+ *
+ * @param start the start padding in pixels, or -1 to use computed padding
+ * @param top the top padding in pixels, or -1 to use computed padding
+ * @param end the end padding in pixels, or -1 to use computed padding
+ * @param bottom the bottom padding in pixels, or -1 to use computed
+ * padding
+ * @attr ref android.R.styleable#LayerDrawable_paddingStart
+ * @attr ref android.R.styleable#LayerDrawable_paddingTop
+ * @attr ref android.R.styleable#LayerDrawable_paddingEnd
+ * @attr ref android.R.styleable#LayerDrawable_paddingBottom
+ * @see #setPadding(int, int, int, int)
+ */
+ public void setPaddingRelative(int start, int top, int end, int bottom) {
+ final LayerState layerState = mLayerState;
+ layerState.mPaddingStart = start;
+ layerState.mPaddingTop = top;
+ layerState.mPaddingEnd = end;
+ layerState.mPaddingBottom = bottom;
+
+ // Clear absolute padding values.
+ layerState.mPaddingLeft = -1;
+ layerState.mPaddingRight = -1;
+ }
+
+ /**
+ * Returns the left padding in pixels.
+ * <p>
+ * A return value of {@code -1} means there is no explicit padding set for
+ * this dimension. As a result, the value for this dimension returned by
+ * {@link #getPadding(Rect)} will be computed from the child layers
+ * according to the padding mode (see {@link #getPaddingMode()}.
+ *
+ * @return the left padding in pixels, or -1 if not explicitly specified
+ * @see #setPadding(int, int, int, int)
+ * @see #getPadding(Rect)
+ */
+ public int getLeftPadding() {
+ return mLayerState.mPaddingLeft;
+ }
+
+ /**
+ * Returns the right padding in pixels.
+ * <p>
+ * A return value of {@code -1} means there is no explicit padding set for
+ * this dimension. As a result, the value for this dimension returned by
+ * {@link #getPadding(Rect)} will be computed from the child layers
+ * according to the padding mode (see {@link #getPaddingMode()}.
+ *
+ * @return the right padding in pixels, or -1 if not explicitly specified
+ * @see #setPadding(int, int, int, int)
+ * @see #getPadding(Rect)
+ */
+ public int getRightPadding() {
+ return mLayerState.mPaddingRight;
+ }
+
+ /**
+ * Returns the start padding in pixels.
+ * <p>
+ * A return value of {@code -1} means there is no explicit padding set for
+ * this dimension. As a result, the value for this dimension returned by
+ * {@link #getPadding(Rect)} will be computed from the child layers
+ * according to the padding mode (see {@link #getPaddingMode()}.
+ *
+ * @return the start padding in pixels, or -1 if not explicitly specified
+ * @see #setPaddingRelative(int, int, int, int)
+ * @see #getPadding(Rect)
+ */
+ public int getStartPadding() {
+ return mLayerState.mPaddingStart;
+ }
+
+ /**
+ * Returns the end padding in pixels.
+ * <p>
+ * A return value of {@code -1} means there is no explicit padding set for
+ * this dimension. As a result, the value for this dimension returned by
+ * {@link #getPadding(Rect)} will be computed from the child layers
+ * according to the padding mode (see {@link #getPaddingMode()}.
+ *
+ * @return the end padding in pixels, or -1 if not explicitly specified
+ * @see #setPaddingRelative(int, int, int, int)
+ * @see #getPadding(Rect)
+ */
+ public int getEndPadding() {
+ return mLayerState.mPaddingEnd;
+ }
+
+ /**
+ * Returns the top padding in pixels.
+ * <p>
+ * A return value of {@code -1} means there is no explicit padding set for
+ * this dimension. As a result, the value for this dimension returned by
+ * {@link #getPadding(Rect)} will be computed from the child layers
+ * according to the padding mode (see {@link #getPaddingMode()}.
+ *
+ * @return the top padding in pixels, or -1 if not explicitly specified
+ * @see #setPadding(int, int, int, int)
+ * @see #setPaddingRelative(int, int, int, int)
+ * @see #getPadding(Rect)
+ */
+ public int getTopPadding() {
+ return mLayerState.mPaddingTop;
+ }
+
+ /**
+ * Returns the bottom padding in pixels.
+ * <p>
+ * A return value of {@code -1} means there is no explicit padding set for
+ * this dimension. As a result, the value for this dimension returned by
+ * {@link #getPadding(Rect)} will be computed from the child layers
+ * according to the padding mode (see {@link #getPaddingMode()}.
+ *
+ * @return the bottom padding in pixels, or -1 if not explicitly specified
+ * @see #setPadding(int, int, int, int)
+ * @see #setPaddingRelative(int, int, int, int)
+ * @see #getPadding(Rect)
+ */
+ public int getBottomPadding() {
+ return mLayerState.mPaddingBottom;
+ }
+
private void computeNestedPadding(Rect padding) {
padding.left = 0;
padding.top = 0;
@@ -1109,8 +1330,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
/**
- * Sets the opacity of this drawable directly, instead of collecting the
- * states from the layers
+ * Sets the opacity of this drawable directly instead of collecting the
+ * states from the layers.
*
* @param opacity The opacity to use, or {@link PixelFormat#UNKNOWN
* PixelFormat.UNKNOWN} for the default behavior
@@ -1120,13 +1341,13 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @see PixelFormat#OPAQUE
*/
public void setOpacity(int opacity) {
- mOpacityOverride = opacity;
+ mLayerState.mOpacityOverride = opacity;
}
@Override
public int getOpacity() {
- if (mOpacityOverride != PixelFormat.UNKNOWN) {
- return mOpacityOverride;
+ if (mLayerState.mOpacityOverride != PixelFormat.UNKNOWN) {
+ return mLayerState.mOpacityOverride;
}
return mLayerState.getOpacity();
}
@@ -1265,12 +1486,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* dimension, defaults to START or TOP. Otherwise, defaults to FILL to
* preserve legacy behavior.
*
- * @param gravity
- * @param width
- * @param height
- * @return
+ * @param gravity layer gravity
+ * @param width width of the layer if set, -1 otherwise
+ * @param height height of the layer if set, -1 otherwise
+ * @return the default gravity for the layer
*/
- private int resolveGravity(int gravity, int width, int height) {
+ private static int resolveGravity(int gravity, int width, int height) {
if (!Gravity.isHorizontal(gravity)) {
if (width < 0) {
gravity |= Gravity.FILL_HORIZONTAL;
@@ -1504,6 +1725,14 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
ChildDrawable[] mChildren;
int[] mThemeAttrs;
+ int mPaddingTop = -1;
+ int mPaddingBottom = -1;
+ int mPaddingLeft = -1;
+ int mPaddingRight = -1;
+ int mPaddingStart = -1;
+ int mPaddingEnd = -1;
+ int mOpacityOverride = PixelFormat.UNKNOWN;
+
int mChangingConfigurations;
int mChildrenChangingConfigurations;
@@ -1540,6 +1769,13 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
mAutoMirrored = orig.mAutoMirrored;
mPaddingMode = orig.mPaddingMode;
mThemeAttrs = orig.mThemeAttrs;
+ mPaddingTop = orig.mPaddingTop;
+ mPaddingBottom = orig.mPaddingBottom;
+ mPaddingLeft = orig.mPaddingLeft;
+ mPaddingRight = orig.mPaddingRight;
+ mPaddingStart = orig.mPaddingStart;
+ mPaddingEnd = orig.mPaddingEnd;
+ mOpacityOverride = orig.mOpacityOverride;
} else {
mNum = 0;
mChildren = null;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 6731a1749286..f67dcb3cd0c9 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -323,7 +323,21 @@ public class RippleDrawable extends LayerDrawable {
*/
@Override
public boolean isProjected() {
- return getNumberOfLayers() == 0;
+ // If the maximum radius is contained entirely within the bounds, we
+ // don't need to project this ripple.
+ final int radius = mState.mMaxRadius;
+ final Rect bounds = getBounds();
+ if (radius != RADIUS_AUTO && radius <= bounds.width() / 2
+ && radius <= bounds.height() / 2) {
+ return false;
+ }
+
+ // Otherwise, if the layer is bounded then we don't need to project.
+ return !isBounded();
+ }
+
+ private boolean isBounded() {
+ return getNumberOfLayers() > 0;
}
@Override
@@ -545,7 +559,7 @@ public class RippleDrawable extends LayerDrawable {
y = mHotspotBounds.exactCenterY();
}
- final boolean isBounded = !isProjected();
+ final boolean isBounded = isBounded();
mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded);
}
@@ -866,7 +880,7 @@ public class RippleDrawable extends LayerDrawable {
@Override
public Rect getDirtyBounds() {
- if (isProjected()) {
+ if (!isBounded()) {
final Rect drawingBounds = mDrawingBounds;
final Rect dirtyBounds = mDirtyBounds;
dirtyBounds.set(drawingBounds);