summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Abodunrinwa Toki <toki@google.com> 2018-01-18 01:11:05 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-01-18 01:11:05 +0000
commitf317e583e49a31312cef05928a708c2df97a44e8 (patch)
tree3f316585c273ea4be69ba8121698e6790cbfb076
parent98602c5b4bf07f61d0da0de58699f8a0fbac769e (diff)
parente94a75a1a0896e583725f45b97affb0e310ee6ec (diff)
Merge "Implement text baseline attributes for TextView."
-rw-r--r--api/current.txt8
-rw-r--r--core/java/android/widget/TextView.java153
-rw-r--r--core/res/res/values/attrs.xml9
-rw-r--r--core/res/res/values/public.xml3
4 files changed, 173 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt
index 4595cf8520d0..9398d72615f2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -602,6 +602,7 @@ package android {
field public static final int fingerprintAuthDrawable = 16844008; // 0x10104e8
field public static final int finishOnCloseSystemDialogs = 16843431; // 0x10102a7
field public static final int finishOnTaskLaunch = 16842772; // 0x1010014
+ field public static final int firstBaselineToTopHeight = 16844157; // 0x101057d
field public static final int firstDayOfWeek = 16843581; // 0x101033d
field public static final int fitsSystemWindows = 16842973; // 0x10100dd
field public static final int flipInterval = 16843129; // 0x1010179
@@ -798,6 +799,7 @@ package android {
field public static final int largeHeap = 16843610; // 0x101035a
field public static final int largeScreens = 16843398; // 0x1010286
field public static final int largestWidthLimitDp = 16843622; // 0x1010366
+ field public static final int lastBaselineToBottomHeight = 16844158; // 0x101057e
field public static final int launchMode = 16842781; // 0x101001d
field public static final int launchTaskBehindSourceAnimation = 16843922; // 0x1010492
field public static final int launchTaskBehindTargetAnimation = 16843921; // 0x1010491
@@ -855,6 +857,7 @@ package android {
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
field public static final int level = 16844032; // 0x1010500
+ field public static final int lineHeight = 16844159; // 0x101057f
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -52520,6 +52523,7 @@ package android.widget {
method public int getExtendedPaddingBottom();
method public int getExtendedPaddingTop();
method public android.text.InputFilter[] getFilters();
+ method public int getFirstBaselineToTopHeight();
method public java.lang.String getFontFeatureSettings();
method public java.lang.String getFontVariationSettings();
method public boolean getFreezesText();
@@ -52537,6 +52541,7 @@ package android.widget {
method public int getInputType();
method public int getJustificationMode();
method public final android.text.method.KeyListener getKeyListener();
+ method public int getLastBaselineToBottomHeight();
method public final android.text.Layout getLayout();
method public float getLetterSpacing();
method public int getLineBounds(int, android.graphics.Rect);
@@ -52633,6 +52638,7 @@ package android.widget {
method public void setExtractedText(android.view.inputmethod.ExtractedText);
method public void setFallbackLineSpacing(boolean);
method public void setFilters(android.text.InputFilter[]);
+ method public void setFirstBaselineToTopHeight(int);
method public void setFontFeatureSettings(java.lang.String);
method public boolean setFontVariationSettings(java.lang.String);
method protected boolean setFrame(int, int, int, int);
@@ -52654,7 +52660,9 @@ package android.widget {
method public void setInputType(int);
method public void setJustificationMode(int);
method public void setKeyListener(android.text.method.KeyListener);
+ method public void setLastBaselineToBottomHeight(int);
method public void setLetterSpacing(float);
+ method public void setLineHeight(int);
method public void setLineSpacing(float, float);
method public void setLines(int);
method public final void setLinkTextColor(int);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0399fc98d016..dac6c0269539 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -27,8 +27,10 @@ import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.FloatRange;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.annotation.Size;
import android.annotation.StringRes;
import android.annotation.StyleRes;
@@ -52,6 +54,7 @@ import android.graphics.BaseCanvas;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -924,6 +927,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int inputType = EditorInfo.TYPE_NULL;
a = theme.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
+ int firstBaselineToTopHeight = -1;
+ int lastBaselineToBottomHeight = -1;
+ int lineHeight = -1;
readTextAppearance(context, a, attributes, true /* styleArray */);
@@ -1249,6 +1255,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextView_justificationMode:
mJustificationMode = a.getInt(attr, Layout.JUSTIFICATION_MODE_NONE);
break;
+
+ case com.android.internal.R.styleable.TextView_firstBaselineToTopHeight:
+ firstBaselineToTopHeight = a.getDimensionPixelSize(attr, -1);
+ break;
+
+ case com.android.internal.R.styleable.TextView_lastBaselineToBottomHeight:
+ lastBaselineToBottomHeight = a.getDimensionPixelSize(attr, -1);
+ break;
+
+ case com.android.internal.R.styleable.TextView_lineHeight:
+ lineHeight = a.getDimensionPixelSize(attr, -1);
+ break;
}
}
@@ -1563,6 +1581,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} else {
mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE;
}
+
+ if (firstBaselineToTopHeight >= 0) {
+ setFirstBaselineToTopHeight(firstBaselineToTopHeight);
+ }
+ if (lastBaselineToBottomHeight >= 0) {
+ setLastBaselineToBottomHeight(lastBaselineToBottomHeight);
+ }
+ if (lineHeight >= 0) {
+ setLineHeight(lineHeight);
+ }
}
/**
@@ -3165,6 +3193,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ /**
+ * @inheritDoc
+ *
+ * @see #setFirstBaselineToTopHeight(int)
+ * @see #setLastBaselineToBottomHeight(int)
+ */
@Override
public void setPadding(int left, int top, int right, int bottom) {
if (left != mPaddingLeft
@@ -3179,6 +3213,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
invalidate();
}
+ /**
+ * @inheritDoc
+ *
+ * @see #setFirstBaselineToTopHeight(int)
+ * @see #setLastBaselineToBottomHeight(int)
+ */
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
if (start != getPaddingStart()
@@ -3194,6 +3234,97 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Updates the top padding of the TextView so that {@code firstBaselineToTopHeight} is
+ * equal to the distance between the firt text baseline and the top of this TextView.
+ * <strong>Note</strong> that if {@code FontMetrics.top} or {@code FontMetrics.ascent} was
+ * already greater than {@code firstBaselineToTopHeight}, the top padding is not updated.
+ *
+ * @param firstBaselineToTopHeight distance between first baseline to top of the container
+ * in pixels
+ *
+ * @see #getFirstBaselineToTopHeight()
+ * @see #setPadding(int, int, int, int)
+ * @see #setPaddingRelative(int, int, int, int)
+ *
+ * @attr ref android.R.styleable#TextView_firstBaselineToTopHeight
+ */
+ public void setFirstBaselineToTopHeight(@Px @IntRange(from = 0) int firstBaselineToTopHeight) {
+ Preconditions.checkArgumentNonnegative(firstBaselineToTopHeight);
+
+ final FontMetricsInt fontMetrics = getPaint().getFontMetricsInt();
+ final int fontMetricsTop;
+ if (getIncludeFontPadding()) {
+ fontMetricsTop = fontMetrics.top;
+ } else {
+ fontMetricsTop = fontMetrics.ascent;
+ }
+
+ // TODO: Decide if we want to ignore density ratio (i.e. when the user changes font size
+ // in settings). At the moment, we don't.
+
+ if (firstBaselineToTopHeight > Math.abs(fontMetricsTop)) {
+ final int paddingTop = firstBaselineToTopHeight - (-fontMetricsTop);
+ setPadding(getPaddingLeft(), paddingTop, getPaddingRight(), getPaddingBottom());
+ }
+ }
+
+ /**
+ * Updates the bottom padding of the TextView so that {@code lastBaselineToBottomHeight} is
+ * equal to the distance between the last text baseline and the bottom of this TextView.
+ * <strong>Note</strong> that if {@code FontMetrics.bottom} or {@code FontMetrics.descent} was
+ * already greater than {@code lastBaselineToBottomHeight}, the bottom padding is not updated.
+ *
+ * @param lastBaselineToBottomHeight distance between last baseline to bottom of the container
+ * in pixels
+ *
+ * @see #getLastBaselineToBottomHeight()
+ * @see #setPadding(int, int, int, int)
+ * @see #setPaddingRelative(int, int, int, int)
+ *
+ * @attr ref android.R.styleable#TextView_lastBaselineToBottomHeight
+ */
+ public void setLastBaselineToBottomHeight(
+ @Px @IntRange(from = 0) int lastBaselineToBottomHeight) {
+ Preconditions.checkArgumentNonnegative(lastBaselineToBottomHeight);
+
+ final FontMetricsInt fontMetrics = getPaint().getFontMetricsInt();
+ final int fontMetricsBottom;
+ if (getIncludeFontPadding()) {
+ fontMetricsBottom = fontMetrics.bottom;
+ } else {
+ fontMetricsBottom = fontMetrics.descent;
+ }
+
+ // TODO: Decide if we want to ignore density ratio (i.e. when the user changes font size
+ // in settings). At the moment, we don't.
+
+ if (lastBaselineToBottomHeight > Math.abs(fontMetricsBottom)) {
+ final int paddingBottom = lastBaselineToBottomHeight - fontMetricsBottom;
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+ }
+ }
+
+ /**
+ * Returns the distance between the first text baseline and the top of this TextView.
+ *
+ * @see #setFirstBaselineToTopHeight(int)
+ * @attr ref android.R.styleable#TextView_firstBaselineToTopHeight
+ */
+ public int getFirstBaselineToTopHeight() {
+ return getPaddingTop() - getPaint().getFontMetricsInt().top;
+ }
+
+ /**
+ * Returns the distance between the last text baseline and the bottom of this TextView.
+ *
+ * @see #setLastBaselineToBottomHeight(int)
+ * @attr ref android.R.styleable#TextView_lastBaselineToBottomHeight
+ */
+ public int getLastBaselineToBottomHeight() {
+ return getPaddingBottom() + getPaint().getFontMetricsInt().bottom;
+ }
+
+ /**
* Gets the autolink mask of the text. See {@link
* android.text.util.Linkify#ALL Linkify.ALL} and peers for
* possible values.
@@ -4975,6 +5106,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets an explicit line height for this TextView. This is equivalent to the vertical distance
+ * between subsequent baselines in the TextView.
+ *
+ * @param lineHeight the line height in pixels
+ *
+ * @see #setLineSpacing(float, float)
+ * @see #getLineSpacing()
+ *
+ * @attr ref android.R.styleable#TextView_lineHeight
+ */
+ public void setLineHeight(@Px @IntRange(from = 0) int lineHeight) {
+ Preconditions.checkArgumentNonnegative(lineHeight);
+
+ final int fontHeight = getPaint().getFontMetricsInt(null);
+ // Make sure we don't setLineSpacing if it's not needed to avoid unnecessary redraw.
+ if (lineHeight != fontHeight) {
+ // Set lineSpacingExtra by the difference of lineSpacing with lineHeight
+ setLineSpacing(lineHeight - fontHeight, 1f);
+ }
+ }
+
+ /**
* Convenience method to append the specified text to the TextView's
* display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
* if it was not already editable.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index addbbf5c6ce9..fd33dc9a32dc 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4739,6 +4739,15 @@
<!-- Extra spacing between lines of text, as a multiplier. The value will not be applied
for the last line of text.-->
<attr name="lineSpacingMultiplier" format="float" />
+ <!-- Explicit height between lines of text. If set, this will override the values set
+ for lineSpacingExtra and lineSpacingMultiplier. -->
+ <attr name="lineHeight" format="dimension" />
+ <!-- Distance from the top of the TextView to the first text baseline. If set, this
+ overrides the value set for paddingTop. -->
+ <attr name="firstBaselineToTopHeight" format="dimension" />
+ <!-- Distance from the bottom of the TextView to the last text baseline. If set, this
+ overrides the value set for paddingBottom. -->
+ <attr name="lastBaselineToBottomHeight" format="dimension" />
<!-- The number of times to repeat the marquee animation. Only applied if the
TextView has marquee enabled. -->
<attr name="marqueeRepeatLimit" format="integer">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 58ae76cdf160..656add664022 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2862,6 +2862,9 @@
<public name="appComponentFactory" />
<public name="fallbackLineSpacing" />
<public name="accessibilityPaneTitle" />
+ <public name="firstBaselineToTopHeight" />
+ <public name="lastBaselineToBottomHeight" />
+ <public name="lineHeight" />
</public-group>
<public-group type="style" first-id="0x010302e0">