diff options
| -rw-r--r-- | core/java/android/text/Layout.java | 11 | ||||
| -rw-r--r-- | core/java/android/text/StaticLayout.java | 85 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 45 |
3 files changed, 90 insertions, 51 deletions
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index f9afcc7ac36c..fd6fc7dc0860 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -634,6 +634,17 @@ public abstract class Layout { } /** + * Return the total height of this layout. + * + * @param cap if true and max lines is set, returns the height of the layout at the max lines. + * + * @hide + */ + public int getHeight(boolean cap) { + return getHeight(); + } + + /** * Return the base alignment of this layout. */ public final Alignment getAlignment() { diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index bdbe8b0f9a24..081be3afd6d3 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -836,7 +836,7 @@ public class StaticLayout extends Layout { here = endPos; breakIndex++; - if (mLineCount >= mMaximumVisibleLineCount) { + if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) { return; } } @@ -920,7 +920,25 @@ public class StaticLayout extends Layout { boolean firstLine = (j == 0); boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount); - boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd); + + if (ellipsize != null) { + // If there is only one line, then do any type of ellipsis except when it is MARQUEE + // if there are multiple lines, just allow END ellipsis on the last line + boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); + + boolean doEllipsis = + (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && + ellipsize != TextUtils.TruncateAt.MARQUEE) || + (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && + ellipsize == TextUtils.TruncateAt.END); + if (doEllipsis) { + calculateEllipsis(start, end, widths, widthStart, + ellipsisWidth, ellipsize, j, + textWidth, paint, forceEllipsis); + } + } + + boolean lastLine = mEllipsized || (end == bufEnd); if (firstLine) { if (trackPad) { @@ -944,7 +962,6 @@ public class StaticLayout extends Layout { } } - if (needMultiply && !lastLine) { double ex = (below - above) * (spacingmult - 1) + spacingadd; if (ex >= 0) { @@ -960,6 +977,15 @@ public class StaticLayout extends Layout { lines[off + TOP] = v; lines[off + DESCENT] = below + extra; + // special case for non-ellipsized last visible line when maxLines is set + // store the height as if it was ellipsized + if (!mEllipsized && currentLineIsTheLastVisibleOne) { + // below calculation as if it was the last line + int maxLineBelow = includePad ? bottom : below; + // similar to the calculation of v below, without the extra. + mMaxLineHeight = v + (maxLineBelow - above); + } + v += (below - above) + extra; lines[off + mColumns + START] = end; lines[off + mColumns + TOP] = v; @@ -981,23 +1007,6 @@ public class StaticLayout extends Layout { start - widthStart, end - start); } - if (ellipsize != null) { - // If there is only one line, then do any type of ellipsis except when it is MARQUEE - // if there are multiple lines, just allow END ellipsis on the last line - boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); - - boolean doEllipsis = - (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && - ellipsize != TextUtils.TruncateAt.MARQUEE) || - (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && - ellipsize == TextUtils.TruncateAt.END); - if (doEllipsis) { - calculateEllipsis(start, end, widths, widthStart, - ellipsisWidth, ellipsize, j, - textWidth, paint, forceEllipsis); - } - } - mLineCount++; return v; } @@ -1105,7 +1114,7 @@ public class StaticLayout extends Layout { } } } - + mEllipsized = true; mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart; mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount; } @@ -1243,6 +1252,25 @@ public class StaticLayout extends Layout { return mEllipsizedWidth; } + /** + * Return the total height of this layout. + * + * @param cap if true and max lines is set, returns the height of the layout at the max lines. + * + * @hide + */ + public int getHeight(boolean cap) { + if (cap && mLineCount >= mMaximumVisibleLineCount && mMaxLineHeight == -1 && + Log.isLoggable(TAG, Log.WARN)) { + Log.w(TAG, "maxLineHeight should not be -1. " + + " maxLines:" + mMaximumVisibleLineCount + + " lineCount:" + mLineCount); + } + + return cap && mLineCount >= mMaximumVisibleLineCount && mMaxLineHeight != -1 ? + mMaxLineHeight : super.getHeight(); + } + private static native long nNewBuilder(); private static native void nFreeBuilder(long nativePtr); private static native void nFinishBuilder(long nativePtr); @@ -1281,6 +1309,21 @@ public class StaticLayout extends Layout { private int mColumns; private int mEllipsizedWidth; + /** + * Keeps track if ellipsize is applied to the text. + */ + private boolean mEllipsized; + + /** + * If maxLines is set, ellipsize is not set, and the actual line count of text is greater than + * or equal to maxLine, this variable holds the ideal visual height of the maxLine'th line + * starting from the top of the layout. If maxLines is not set its value will be -1. + * + * The value is the same as getLineTop(maxLines) for ellipsized version where structurally no + * more than maxLines is contained. + */ + private int mMaxLineHeight = -1; + private static final int COLUMNS_NORMAL = 4; private static final int COLUMNS_ELLIPSIZE = 6; private static final int START = 0; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9c48cf8e8806..73af7558100f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5157,7 +5157,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * call {@link InputMethodManager#restartInput(View)}.</p> * @param hintLocales List of the languages that the user is supposed to switch to no matter * what input method subtype is currently used. Set {@code null} to clear the current "hint". - * @see #getImeHIntLocales() + * @see #getImeHintLocales() * @see android.view.inputmethod.EditorInfo#hintLocales */ public void setImeHintLocales(@Nullable LocaleList hintLocales) { @@ -7000,11 +7000,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) - .setHyphenationFrequency(mHyphenationFrequency); + .setHyphenationFrequency(mHyphenationFrequency) + .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); if (shouldEllipsize) { builder.setEllipsize(mEllipsize) - .setEllipsizedWidth(ellipsisWidth) - .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + .setEllipsizedWidth(ellipsisWidth); } mHintLayout = builder.build(); } @@ -7091,11 +7091,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) - .setHyphenationFrequency(mHyphenationFrequency); + .setHyphenationFrequency(mHyphenationFrequency) + .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); if (shouldEllipsize) { builder.setEllipsize(effectiveEllipsize) - .setEllipsizedWidth(ellipsisWidth) - .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + .setEllipsizedWidth(ellipsisWidth); } // TODO: explore always setting maxLines result = builder.build(); @@ -7367,9 +7367,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return 0; } - int linecount = layout.getLineCount(); - int pad = getCompoundPaddingTop() + getCompoundPaddingBottom(); - int desired = layout.getLineTop(linecount); + /* + * Don't cap the hint to a certain number of lines. + * (Do cap it, though, if we have a maximum pixel height.) + */ + int desired = layout.getHeight(cap); final Drawables dr = mDrawables; if (dr != null) { @@ -7377,31 +7379,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener desired = Math.max(desired, dr.mDrawableHeightRight); } - desired += pad; - - if (mMaxMode == LINES) { - /* - * Don't cap the hint to a certain number of lines. - * (Do cap it, though, if we have a maximum pixel height.) - */ - if (cap) { - if (linecount > mMaximum) { - desired = layout.getLineTop(mMaximum); + desired += getCompoundPaddingTop() + getCompoundPaddingBottom(); - if (dr != null) { - desired = Math.max(desired, dr.mDrawableHeightLeft); - desired = Math.max(desired, dr.mDrawableHeightRight); - } - - desired += pad; - linecount = mMaximum; - } - } - } else { + if (mMaxMode != LINES) { desired = Math.min(desired, mMaximum); } if (mMinMode == LINES) { + int linecount = layout.getLineCount(); if (linecount < mMinimum) { desired += getLineHeight() * (mMinimum - linecount); } |