summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorFabrice Di Meglio <fdimeglio@google.com>2011-07-12 18:24:27 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-07-12 18:24:27 -0700
commita6c53c79390e719ae425d38d6d80587e0d017ef3 (patch)
tree1394b3831265196a518b03bee010f7c220910fe4 /core/java
parentc93ffea268b49e8697c767508dc5afe1a2338c05 (diff)
parenta3b6b95f9943b53d25d44a35082f817802d4eccd (diff)
downloadframeworks_base-a6c53c79390e719ae425d38d6d80587e0d017ef3.zip
frameworks_base-a6c53c79390e719ae425d38d6d80587e0d017ef3.tar.gz
frameworks_base-a6c53c79390e719ae425d38d6d80587e0d017ef3.tar.bz2
Merge "Introduce TextView drawableStart and drawableEnd"
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/widget/TextView.java406
1 files changed, 399 insertions, 7 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index aae3809..6b4e454 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -260,9 +260,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
class Drawables {
final Rect mCompoundRect = new Rect();
- Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight;
- int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
- int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
+ Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
+ mDrawableStart, mDrawableEnd;
+ int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
+ mDrawableSizeStart, mDrawableSizeEnd;
+ int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight,
+ mDrawableHeightStart, mDrawableHeightEnd;
int mDrawablePadding;
}
private Drawables mDrawables;
@@ -352,6 +355,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
}
+ private boolean bResolvedDrawables = false;
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -494,7 +499,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int buffertype = 0;
boolean selectallonfocus = false;
Drawable drawableLeft = null, drawableTop = null, drawableRight = null,
- drawableBottom = null;
+ drawableBottom = null, drawableStart = null, drawableEnd = null;
int drawablePadding = 0;
int ellipsize = -1;
boolean singleLine = false;
@@ -571,6 +576,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
drawableBottom = a.getDrawable(attr);
break;
+ case com.android.internal.R.styleable.TextView_drawableStart:
+ drawableStart = a.getDrawable(attr);
+ break;
+
+ case com.android.internal.R.styleable.TextView_drawableEnd:
+ drawableEnd = a.getDrawable(attr);
+ break;
+
case com.android.internal.R.styleable.TextView_drawablePadding:
drawablePadding = a.getDimensionPixelSize(attr, drawablePadding);
break;
@@ -980,6 +993,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setCompoundDrawablesWithIntrinsicBounds(
drawableLeft, drawableTop, drawableRight, drawableBottom);
+ setRelativeDrawablesIfNeeded(drawableStart, drawableEnd);
setCompoundDrawablePadding(drawablePadding);
// Same as setSingleLine(), but make sure the transformation method and the maximum number
@@ -1105,6 +1119,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setTypeface(tf, styleIndex);
}
+ private void setRelativeDrawablesIfNeeded(Drawable start, Drawable end) {
+ boolean hasRelativeDrawables = (start != null) || (end != null);
+ if (hasRelativeDrawables) {
+ Drawables dr = mDrawables;
+ if (dr == null) {
+ mDrawables = dr = new Drawables();
+ }
+ final Rect compoundRect = dr.mCompoundRect;
+ int[] state = getDrawableState();
+ if (start != null) {
+ start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+ start.setState(state);
+ start.copyBounds(compoundRect);
+ start.setCallback(this);
+
+ dr.mDrawableStart = start;
+ dr.mDrawableSizeStart = compoundRect.width();
+ dr.mDrawableHeightStart = compoundRect.height();
+ } else {
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ }
+ if (end != null) {
+ end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+ end.setState(state);
+ end.copyBounds(compoundRect);
+ end.setCallback(this);
+
+ dr.mDrawableEnd = end;
+ dr.mDrawableSizeEnd = compoundRect.width();
+ dr.mDrawableHeightEnd = compoundRect.height();
+ } else {
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+ }
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (enabled == isEnabled()) {
@@ -1411,6 +1461,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns the start padding of the view, plus space for the start
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getCompoundPaddingStart() {
+ resolveDrawables();
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ return getCompoundPaddingLeft();
+ case LAYOUT_DIRECTION_RTL:
+ return getCompoundPaddingRight();
+ }
+ }
+
+ /**
+ * Returns the end padding of the view, plus space for the end
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getCompoundPaddingEnd() {
+ resolveDrawables();
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ return getCompoundPaddingRight();
+ case LAYOUT_DIRECTION_RTL:
+ return getCompoundPaddingLeft();
+ }
+ }
+
+ /**
* Returns the extended top padding of the view, including both the
* top Drawable if any and any extra space to keep more than maxLines
* of text from showing. It is only valid to call this after measuring.
@@ -1493,6 +1577,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns the total start padding of the view, including the start
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getTotalPaddingStart() {
+ return getCompoundPaddingStart();
+ }
+
+ /**
+ * Returns the total end padding of the view, including the end
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getTotalPaddingEnd() {
+ return getCompoundPaddingEnd();
+ }
+
+ /**
* Returns the total top padding of the view, including the top
* Drawable if any, the extra space to keep more than maxLines
* from showing, and the vertical offset for gravity, if any.
@@ -1679,6 +1783,185 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use null if you do not
+ * want a Drawable there. The Drawables must already have had
+ * {@link Drawable#setBounds} called.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelative(Drawable start, Drawable top,
+ Drawable end, Drawable bottom) {
+ Drawables dr = mDrawables;
+
+ final boolean drawables = start != null || top != null
+ || end != null || bottom != null;
+
+ if (!drawables) {
+ // Clearing drawables... can we free the data structure?
+ if (dr != null) {
+ if (dr.mDrawablePadding == 0) {
+ mDrawables = null;
+ } else {
+ // We need to retain the last set padding, so just clear
+ // out all of the fields in the existing structure.
+ if (dr.mDrawableStart != null) dr.mDrawableStart.setCallback(null);
+ dr.mDrawableStart = null;
+ if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
+ dr.mDrawableTop = null;
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.setCallback(null);
+ dr.mDrawableEnd = null;
+ if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
+ dr.mDrawableBottom = null;
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+ dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+ }
+ }
+ } else {
+ if (dr == null) {
+ mDrawables = dr = new Drawables();
+ }
+
+ if (dr.mDrawableStart != start && dr.mDrawableStart != null) {
+ dr.mDrawableStart.setCallback(null);
+ }
+ dr.mDrawableStart = start;
+
+ if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
+ dr.mDrawableTop.setCallback(null);
+ }
+ dr.mDrawableTop = top;
+
+ if (dr.mDrawableEnd != end && dr.mDrawableEnd != null) {
+ dr.mDrawableEnd.setCallback(null);
+ }
+ dr.mDrawableEnd = end;
+
+ if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
+ dr.mDrawableBottom.setCallback(null);
+ }
+ dr.mDrawableBottom = bottom;
+
+ final Rect compoundRect = dr.mCompoundRect;
+ int[] state;
+
+ state = getDrawableState();
+
+ if (start != null) {
+ start.setState(state);
+ start.copyBounds(compoundRect);
+ start.setCallback(this);
+ dr.mDrawableSizeStart = compoundRect.width();
+ dr.mDrawableHeightStart = compoundRect.height();
+ } else {
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ }
+
+ if (end != null) {
+ end.setState(state);
+ end.copyBounds(compoundRect);
+ end.setCallback(this);
+ dr.mDrawableSizeEnd = compoundRect.width();
+ dr.mDrawableHeightEnd = compoundRect.height();
+ } else {
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+
+ if (top != null) {
+ top.setState(state);
+ top.copyBounds(compoundRect);
+ top.setCallback(this);
+ dr.mDrawableSizeTop = compoundRect.height();
+ dr.mDrawableWidthTop = compoundRect.width();
+ } else {
+ dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+ }
+
+ if (bottom != null) {
+ bottom.setState(state);
+ bottom.copyBounds(compoundRect);
+ bottom.setCallback(this);
+ dr.mDrawableSizeBottom = compoundRect.height();
+ dr.mDrawableWidthBottom = compoundRect.width();
+ } else {
+ dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+ }
+ }
+
+ resolveDrawables();
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use 0 if you do not
+ * want a Drawable there. The Drawables' bounds will be set to
+ * their intrinsic bounds.
+ *
+ * @param start Resource identifier of the start Drawable.
+ * @param top Resource identifier of the top Drawable.
+ * @param end Resource identifier of the end Drawable.
+ * @param bottom Resource identifier of the bottom Drawable.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
+ int bottom) {
+ resetResolvedDrawables();
+ final Resources resources = getContext().getResources();
+ setCompoundDrawablesRelativeWithIntrinsicBounds(
+ start != 0 ? resources.getDrawable(start) : null,
+ top != 0 ? resources.getDrawable(top) : null,
+ end != 0 ? resources.getDrawable(end) : null,
+ bottom != 0 ? resources.getDrawable(bottom) : null);
+ }
+
+ /**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use null if you do not
+ * want a Drawable there. The Drawables' bounds will be set to
+ * their intrinsic bounds.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top,
+ Drawable end, Drawable bottom) {
+
+ resetResolvedDrawables();
+ if (start != null) {
+ start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+ }
+ if (end != null) {
+ end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+ }
+ if (top != null) {
+ top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight());
+ }
+ if (bottom != null) {
+ bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight());
+ }
+ setCompoundDrawablesRelative(start, top, end, bottom);
+ }
+
+ /**
* Returns drawables for the left, top, right, and bottom borders.
*/
public Drawable[] getCompoundDrawables() {
@@ -1693,6 +1976,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns drawables for the start, top, end, and bottom borders.
+ *
+ * @hide
+ */
+ public Drawable[] getCompoundDrawablesRelative() {
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ return new Drawable[] {
+ dr.mDrawableStart, dr.mDrawableTop, dr.mDrawableEnd, dr.mDrawableBottom
+ };
+ } else {
+ return new Drawable[] { null, null, null, null };
+ }
+ }
+
+ /**
* Sets the size of the padding between the compound drawables and
* the text.
*
@@ -2495,6 +2794,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) {
dr.mDrawableRight.setState(state);
}
+ if (dr.mDrawableStart != null && dr.mDrawableStart.isStateful()) {
+ dr.mDrawableStart.setState(state);
+ }
+ if (dr.mDrawableEnd != null && dr.mDrawableEnd.isStateful()) {
+ dr.mDrawableEnd.setState(state);
+ }
}
}
@@ -3546,7 +3851,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mErrorWasChanged = true;
final Drawables dr = mDrawables;
if (dr != null) {
- setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, dr.mDrawableBottom);
+ switch (getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
+ dr.mDrawableBottom);
+ break;
+ case LAYOUT_DIRECTION_RTL:
+ setCompoundDrawables(icon, dr.mDrawableTop, dr.mDrawableRight,
+ dr.mDrawableBottom);
+ break;
+ }
} else {
setCompoundDrawables(null, null, icon, null);
}
@@ -4048,6 +4363,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mSelectionModifierCursorController != null) {
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
+
+ // Resolve drawables as the layout direction has been resolved
+ resolveDrawables();
}
@Override
@@ -4077,6 +4395,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
hideControllers();
+
+ resetResolvedDrawables();
}
@Override
@@ -4111,7 +4431,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final boolean verified = super.verifyDrawable(who);
if (!verified && mDrawables != null) {
return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop ||
- who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom;
+ who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom ||
+ who == mDrawables.mDrawableStart || who == mDrawables.mDrawableEnd;
}
return verified;
}
@@ -4132,6 +4453,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mDrawables.mDrawableBottom != null) {
mDrawables.mDrawableBottom.jumpToCurrentState();
}
+ if (mDrawables.mDrawableStart != null) {
+ mDrawables.mDrawableStart.jumpToCurrentState();
+ }
+ if (mDrawables.mDrawableEnd != null) {
+ mDrawables.mDrawableEnd.jumpToCurrentState();
+ }
}
}
@@ -4192,7 +4519,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mDrawables != null) {
final Drawables drawables = mDrawables;
if (who == drawables.mDrawableLeft || who == drawables.mDrawableRight ||
- who == drawables.mDrawableTop || who == drawables.mDrawableBottom) {
+ who == drawables.mDrawableTop || who == drawables.mDrawableBottom ||
+ who == drawables.mDrawableStart || who == drawables.mDrawableEnd) {
return getResolvedLayoutDirection();
}
}
@@ -4211,6 +4539,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha);
if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha);
if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha);
+ if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha);
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha);
}
return true;
}
@@ -10275,6 +10605,68 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT);
}
+ /**
+ * Subclasses will need to override this method to implement their own way of resolving
+ * drawables depending on the layout direction.
+ *
+ * A call to the super method will be required from the subclasses implementation.
+ *
+ */
+ protected void resolveDrawables() {
+ // No need to resolve twice
+ if (bResolvedDrawables) {
+ return;
+ }
+ // No drawable to resolve
+ if (mDrawables == null) {
+ return;
+ }
+ // No relative drawable to resolve
+ if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) {
+ bResolvedDrawables = true;
+ return;
+ }
+
+ Drawables dr = mDrawables;
+ switch(getResolvedLayoutDirection()) {
+ case LAYOUT_DIRECTION_RTL:
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableRight = dr.mDrawableStart;
+
+ dr.mDrawableSizeRight = dr.mDrawableSizeStart;
+ dr.mDrawableHeightRight = dr.mDrawableHeightStart;
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableLeft = dr.mDrawableEnd;
+
+ dr.mDrawableSizeLeft = dr.mDrawableSizeEnd;
+ dr.mDrawableHeightLeft = dr.mDrawableHeightEnd;
+ }
+ break;
+
+ case LAYOUT_DIRECTION_LTR:
+ default:
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableLeft = dr.mDrawableStart;
+
+ dr.mDrawableSizeLeft = dr.mDrawableSizeStart;
+ dr.mDrawableHeightLeft = dr.mDrawableHeightStart;
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableRight = dr.mDrawableEnd;
+
+ dr.mDrawableSizeRight = dr.mDrawableSizeEnd;
+ dr.mDrawableHeightRight = dr.mDrawableHeightEnd;
+ }
+ break;
+ }
+ bResolvedDrawables = true;
+ }
+
+ protected void resetResolvedDrawables() {
+ bResolvedDrawables = false;
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;