Merge "StaticLayout visual fix for maxLines"

This commit is contained in:
Siyamed Sinir
2016-11-08 00:56:14 +00:00
committed by Android (Google) Code Review
3 changed files with 90 additions and 51 deletions

View File

@@ -633,6 +633,17 @@ public abstract class Layout {
return getLineTop(getLineCount());
}
/**
* 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.
*/

View File

@@ -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;

View File

@@ -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;
desired += getCompoundPaddingTop() + getCompoundPaddingBottom();
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);
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);
}