diff options
| author | 2018-01-18 01:11:05 +0000 | |
|---|---|---|
| committer | 2018-01-18 01:11:05 +0000 | |
| commit | f317e583e49a31312cef05928a708c2df97a44e8 (patch) | |
| tree | 3f316585c273ea4be69ba8121698e6790cbfb076 | |
| parent | 98602c5b4bf07f61d0da0de58699f8a0fbac769e (diff) | |
| parent | e94a75a1a0896e583725f45b97affb0e310ee6ec (diff) | |
Merge "Implement text baseline attributes for TextView."
| -rw-r--r-- | api/current.txt | 8 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 153 | ||||
| -rw-r--r-- | core/res/res/values/attrs.xml | 9 | ||||
| -rw-r--r-- | core/res/res/values/public.xml | 3 |
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"> |