Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 531c30c6 authored by Raph Levien's avatar Raph Levien
Browse files

Expose StaticLayout.Builder publicly

Expose the new Builder pattern for creating StaticLayout. This allows
access to a number of features that have been available to TextView
through a hidden constructor. Some of these features have existed
for a while (mostly maxLines), while others are new (breakStrategy,
indents).

The builder is cleaner and has a better upgrade path than the old
pattern of lots of constructors with varying numbers of arguments.

Bug: 20190561
Change-Id: Ia3cd124825ab0cb469d22d1fc576ad26454545b8
parent ebd66ca6
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -32604,6 +32604,21 @@ package android.text {
    method public int getTopPadding();
    method public int getTopPadding();
  }
  }
  public static final class StaticLayout.Builder {
    method public android.text.StaticLayout build();
    method public static android.text.StaticLayout.Builder obtain(java.lang.CharSequence, int, int, android.text.TextPaint, int);
    method public android.text.StaticLayout.Builder setAlignment(android.text.Layout.Alignment);
    method public android.text.StaticLayout.Builder setBreakStrategy(int);
    method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
    method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
    method public android.text.StaticLayout.Builder setIncludePad(boolean);
    method public android.text.StaticLayout.Builder setIndents(int[], int[]);
    method public android.text.StaticLayout.Builder setLineSpacing(float, float);
    method public android.text.StaticLayout.Builder setMaxLines(int);
    method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
    method public android.text.StaticLayout.Builder setTextDir(android.text.TextDirectionHeuristic);
  }
  public abstract interface TextDirectionHeuristic {
  public abstract interface TextDirectionHeuristic {
    method public abstract boolean isRtl(char[], int, int);
    method public abstract boolean isRtl(char[], int, int);
    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+15 −0
Original line number Original line Diff line number Diff line
@@ -34814,6 +34814,21 @@ package android.text {
    method public int getTopPadding();
    method public int getTopPadding();
  }
  }
  public static final class StaticLayout.Builder {
    method public android.text.StaticLayout build();
    method public static android.text.StaticLayout.Builder obtain(java.lang.CharSequence, int, int, android.text.TextPaint, int);
    method public android.text.StaticLayout.Builder setAlignment(android.text.Layout.Alignment);
    method public android.text.StaticLayout.Builder setBreakStrategy(int);
    method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
    method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
    method public android.text.StaticLayout.Builder setIncludePad(boolean);
    method public android.text.StaticLayout.Builder setIndents(int[], int[]);
    method public android.text.StaticLayout.Builder setLineSpacing(float, float);
    method public android.text.StaticLayout.Builder setMaxLines(int);
    method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
    method public android.text.StaticLayout.Builder setTextDir(android.text.TextDirectionHeuristic);
  }
  public abstract interface TextDirectionHeuristic {
  public abstract interface TextDirectionHeuristic {
    method public abstract boolean isRtl(char[], int, int);
    method public abstract boolean isRtl(char[], int, int);
    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+1 −2
Original line number Original line Diff line number Diff line
@@ -290,8 +290,7 @@ public class DynamicLayout extends Layout
                .setPaint(getPaint())
                .setPaint(getPaint())
                .setWidth(getWidth())
                .setWidth(getWidth())
                .setTextDir(getTextDirectionHeuristic())
                .setTextDir(getTextDirectionHeuristic())
                .setSpacingMult(getSpacingMultiplier())
                .setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
                .setSpacingAdd(getSpacingAdd())
                .setEllipsizedWidth(mEllipsizedWidth)
                .setEllipsizedWidth(mEllipsizedWidth)
                .setEllipsize(mEllipsizeAt)
                .setEllipsize(mEllipsizeAt)
                .setBreakStrategy(mBreakStrategy);
                .setBreakStrategy(mBreakStrategy);
+138 −16
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.text;
package android.text;


import android.annotation.Nullable;
import android.graphics.Paint;
import android.graphics.Paint;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
@@ -46,17 +47,29 @@ public class StaticLayout extends Layout {
    static final String TAG = "StaticLayout";
    static final String TAG = "StaticLayout";


    /**
    /**
     * Builder for static layouts. It would be better if this were a public
     * Builder for static layouts. The builder is a newer pattern for constructing
     * API (as it would offer much greater flexibility for adding new options)
     * StaticLayout objects and should be preferred over the constructors,
     * but for the time being it's just internal.
     * particularly to access newer features. To build a static layout, first
     *
     * call {@link #obtain} with the required arguments (text, paint, and width),
     * @hide
     * then call setters for optional parameters, and finally {@link #build}
     * to build the StaticLayout object. Parameters not explicitly set will get
     * default values.
     */
     */
    public final static class Builder {
    public final static class Builder {
        private Builder() {
        private Builder() {
            mNativePtr = nNewBuilder();
            mNativePtr = nNewBuilder();
        }
        }


        /**
         * Obtain a builder for constructing StaticLayout objects
         *
         * @param source The text to be laid out, optionally with spans
         * @param start The index of the start of the text
         * @param end The index + 1 of the end of the text
         * @param paint The base paint used for layout
         * @param width The width in pixels
         * @return a builder object used for constructing the StaticLayout
         */
        public static Builder obtain(CharSequence source, int start, int end, TextPaint paint,
        public static Builder obtain(CharSequence source, int start, int end, TextPaint paint,
                int width) {
                int width) {
            Builder b = sPool.acquire();
            Builder b = sPool.acquire();
@@ -100,6 +113,18 @@ public class StaticLayout extends Layout {
            return setText(source, 0, source.length());
            return setText(source, 0, source.length());
        }
        }


        /**
         * Set the text. Only useful when re-using the builder, which is done for
         * the internal implementation of {@link DynamicLayout} but not as part
         * of normal {@link StaticLayout} usage.
         *
         * @param source The text to be laid out, optionally with spans
         * @param start The index of the start of the text
         * @param end The index + 1 of the end of the text
         * @return this builder, useful for chaining
         *
         * @hide
         */
        public Builder setText(CharSequence source, int start, int end) {
        public Builder setText(CharSequence source, int start, int end) {
            mText = source;
            mText = source;
            mStart = start;
            mStart = start;
@@ -107,11 +132,27 @@ public class StaticLayout extends Layout {
            return this;
            return this;
        }
        }


        /**
         * Set the paint. Internal for reuse cases only.
         *
         * @param paint The base paint used for layout
         * @return this builder, useful for chaining
         *
         * @hide
         */
        public Builder setPaint(TextPaint paint) {
        public Builder setPaint(TextPaint paint) {
            mPaint = paint;
            mPaint = paint;
            return this;
            return this;
        }
        }


        /**
         * Set the width. Internal for reuse cases only.
         *
         * @param width The width in pixels
         * @return this builder, useful for chaining
         *
         * @hide
         */
        public Builder setWidth(int width) {
        public Builder setWidth(int width) {
            mWidth = width;
            mWidth = width;
            if (mEllipsize == null) {
            if (mEllipsize == null) {
@@ -120,53 +161,126 @@ public class StaticLayout extends Layout {
            return this;
            return this;
        }
        }


        /**
         * Set the alignment. The default is {@link Layout.Alignment#ALIGN_NORMAL}.
         *
         * @param alignment Alignment for the resulting {@link StaticLayout}
         * @return this builder, useful for chaining
         */
        public Builder setAlignment(Alignment alignment) {
        public Builder setAlignment(Alignment alignment) {
            mAlignment = alignment;
            mAlignment = alignment;
            return this;
            return this;
        }
        }


        /**
         * Set the text direction heuristic. The text direction heuristic is used to
         * resolve text direction based per-paragraph based on the input text. The default is
         * {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}.
         *
         * @param textDir text direction heuristic for resolving BiDi behavior.
         * @return this builder, useful for chaining
         */
        public Builder setTextDir(TextDirectionHeuristic textDir) {
        public Builder setTextDir(TextDirectionHeuristic textDir) {
            mTextDir = textDir;
            mTextDir = textDir;
            return this;
            return this;
        }
        }


        // TODO: combine the following, as they're almost always set together?
        /**
        public Builder setSpacingMult(float spacingMult) {
         * Set line spacing parameters. The default is 0.0 for {@code spacingAdd}
            mSpacingMult = spacingMult;
         * and 1.0 for {@code spacingMult}.
            return this;
         *
        }
         * @param spacingAdd line spacing add

         * @param spacingMult line spacing multiplier
        public Builder setSpacingAdd(float spacingAdd) {
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setLineSpacing
         */
        public Builder setLineSpacing(float spacingAdd, float spacingMult) {
            mSpacingAdd = spacingAdd;
            mSpacingAdd = spacingAdd;
            mSpacingMult = spacingMult;
            return this;
            return this;
        }
        }


        /**
         * Set whether to include extra space beyond font ascent and descent (which is
         * needed to avoid clipping in some languages, such as Arabic and Kannada). The
         * default is {@code true}.
         *
         * @param includePad whether to include padding
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setIncludeFontPadding
         */
        public Builder setIncludePad(boolean includePad) {
        public Builder setIncludePad(boolean includePad) {
            mIncludePad = includePad;
            mIncludePad = includePad;
            return this;
            return this;
        }
        }


        // TODO: combine the following?
        /**
         * Set the width as used for ellipsizing purposes, if it differs from the
         * normal layout width. The default is the {@code width}
         * passed to {@link #obtain}.
         *
         * @param ellipsizedWidth width used for ellipsizing, in pixels
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setEllipsize
         */
        public Builder setEllipsizedWidth(int ellipsizedWidth) {
        public Builder setEllipsizedWidth(int ellipsizedWidth) {
            mEllipsizedWidth = ellipsizedWidth;
            mEllipsizedWidth = ellipsizedWidth;
            return this;
            return this;
        }
        }


        public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
        /**
         * Set ellipsizing on the layout. Causes words that are longer than the view
         * is wide, or exceeding the number of lines (see #setMaxLines) in the case
         * of {@link android.text.TextUtils.TruncateAt#END} or
         * {@link android.text.TextUtils.TruncateAt#MARQUEE}, to be ellipsized instead
         * of broken. The default is
         * {@code null}, indicating no ellipsis is to be applied.
         *
         * @param ellipsize type of ellipsis behavior
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setEllipsize
         */
        public Builder setEllipsize(@Nullable TextUtils.TruncateAt ellipsize) {
            mEllipsize = ellipsize;
            mEllipsize = ellipsize;
            return this;
            return this;
        }
        }


        /**
         * Set maximum number of lines. This is particularly useful in the case of
         * ellipsizing, where it changes the layout of the last line. The default is
         * unlimited.
         *
         * @param maxLines maximum number of lines in the layout
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setMaxLines
         */
        public Builder setMaxLines(int maxLines) {
        public Builder setMaxLines(int maxLines) {
            mMaxLines = maxLines;
            mMaxLines = maxLines;
            return this;
            return this;
        }
        }


        /**
         * Set break strategy, useful for selecting high quality or balanced paragraph
         * layout options. The default is {@link Layout#BREAK_STRATEGY_SIMPLE}.
         *
         * @param breakStrategy break strategy for paragraph layout
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setBreakStrategy
         */
        public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
        public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
            mBreakStrategy = breakStrategy;
            mBreakStrategy = breakStrategy;
            return this;
            return this;
        }
        }


        /**
         * Set indents. Arguments are arrays holding an indent amount, one per line, measured in
         * pixels. For lines past the last element in the array, the last element repeats.
         *
         * @param leftIndents array of indent values for left margin, in pixels
         * @param rightIndents array of indent values for right margin, in pixels
         * @return this builder, useful for chaining
         * @see android.widget.TextView#setIndents
         */
        public Builder setIndents(int[] leftIndents, int[] rightIndents) {
        public Builder setIndents(int[] leftIndents, int[] rightIndents) {
            int leftLen = leftIndents == null ? 0 : leftIndents.length;
            int leftLen = leftIndents == null ? 0 : leftIndents.length;
            int rightLen = rightIndents == null ? 0 : rightIndents.length;
            int rightLen = rightIndents == null ? 0 : rightIndents.length;
@@ -220,6 +334,15 @@ public class StaticLayout extends Layout {
            nAddReplacementRun(mNativePtr, start, end, width);
            nAddReplacementRun(mNativePtr, start, end, width);
        }
        }


        /**
         * Build the {@link StaticLayout} after options have been set.
         *
         * <p>Note: the builder object must not be reused in any way after calling this
         * method. Setting parameters after calling this method, or calling it a second
         * time on the same builder object, will likely lead to unexpected results.
         *
         * @return the newly constructed {@link StaticLayout} object
         */
        public StaticLayout build() {
        public StaticLayout build() {
            StaticLayout result = new StaticLayout(this);
            StaticLayout result = new StaticLayout(this);
            Builder.recycle(this);
            Builder.recycle(this);
@@ -332,8 +455,7 @@ public class StaticLayout extends Layout {
        Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth)
        Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth)
            .setAlignment(align)
            .setAlignment(align)
            .setTextDir(textDir)
            .setTextDir(textDir)
            .setSpacingMult(spacingmult)
            .setLineSpacing(spacingadd, spacingmult)
            .setSpacingAdd(spacingadd)
            .setIncludePad(includepad)
            .setIncludePad(includepad)
            .setEllipsizedWidth(ellipsizedWidth)
            .setEllipsizedWidth(ellipsizedWidth)
            .setEllipsize(ellipsize)
            .setEllipsize(ellipsize)
+2 −4
Original line number Original line Diff line number Diff line
@@ -6633,8 +6633,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                        mHint.length(), mTextPaint, hintWidth)
                        mHint.length(), mTextPaint, hintWidth)
                        .setAlignment(alignment)
                        .setAlignment(alignment)
                        .setTextDir(mTextDir)
                        .setTextDir(mTextDir)
                        .setSpacingMult(mSpacingMult)
                        .setLineSpacing(mSpacingAdd, mSpacingMult)
                        .setSpacingAdd(mSpacingAdd)
                        .setIncludePad(mIncludePad)
                        .setIncludePad(mIncludePad)
                        .setBreakStrategy(mBreakStrategy);
                        .setBreakStrategy(mBreakStrategy);
                if (mLeftIndents != null || mRightIndents != null) {
                if (mLeftIndents != null || mRightIndents != null) {
@@ -6723,8 +6722,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    0, mTransformed.length(), mTextPaint, wantWidth)
                    0, mTransformed.length(), mTextPaint, wantWidth)
                    .setAlignment(alignment)
                    .setAlignment(alignment)
                    .setTextDir(mTextDir)
                    .setTextDir(mTextDir)
                    .setSpacingMult(mSpacingMult)
                    .setLineSpacing(mSpacingAdd, mSpacingMult)
                    .setSpacingAdd(mSpacingAdd)
                    .setIncludePad(mIncludePad)
                    .setIncludePad(mIncludePad)
                    .setBreakStrategy(mBreakStrategy);
                    .setBreakStrategy(mBreakStrategy);
            if (mLeftIndents != null || mRightIndents != null) {
            if (mLeftIndents != null || mRightIndents != null) {