android 富文本设计

SpannableString:

This is the class for text whose content is immutable but to which markup objects can be attached and detached.

SpannableString构造的字符串后不可变了,标记对象可以添加和删除

SpannableStringBuilder:

This is the class for text whose content and markup can both be changed.

SpannableStringBuilder 构造的内容和标记对象都可更改

    //object what :对应的各种Span
    // int start:开始应用指定Span的位置,索引从0开始
    //int end:结束应用指定Span的位置,不包含
    //int flags   见Spanned中的描述
    public void setSpan(Object what, int start, int end, int flags) {
        setSpan(true, what, start, end, flags, true/*enforceParagraph*/);
    }

Spanned

This is the interface for text that has markup objects ranges of it.

public interface Spanned
extends CharSequence
{
    //在标志位【start,end)后添加文字,新添加的文字不会有任何设置的属性,前边边的添加的文字会带有设置的what属性
     public static final int SPAN_INCLUSIVE_EXCLUSIVE = SPAN_MARK_MARK;
     //在标志位【start,end)前后添加文字,新添加的文字会有设置的属性
     public static final int SPAN_INCLUSIVE_INCLUSIVE = SPAN_MARK_POINT;
     //在标志位【start,end)前后添加文字,新添加的文字不会有任何设置的属性
     public static final int SPAN_EXCLUSIVE_EXCLUSIVE = SPAN_POINT_MARK;
    //在标志位【start,end)前添加文字,新添加的文字不会有任何设置的属性,后边的添加的文字会带有设置的what属性
     public static final int SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_POINT;
}

Spannable

静态单例 实现工厂方法 返回的SpannableString,
This is the class for text whose content is immutable but to which markup objects can be attached and detached.
就是处理content内容不变。

/**
 * This is the interface for text to which markup objects can be
 * attached and detached.  Not all Spannable classes have mutable text;
 * see {@link Editable} for that.
 */
public interface Spannable
extends Spanned
{
    /**
     * Attach the specified markup object to the range start…end
     * of the text, or move the object to that range if it was already
     * attached elsewhere.  See {@link Spanned} for an explanation of
     * what the flags mean.  The object can be one that has meaning only
     * within your application, or it can be one that the text system will
     * use to affect text display or behavior.  Some noteworthy ones are
     * the subclasses of {@link android.text.style.CharacterStyle} and
     * {@link android.text.style.ParagraphStyle}, and
     * {@link android.text.TextWatcher} and
     * {@link android.text.SpanWatcher}.
     */
    public void setSpan(Object what, int start, int end, int flags);

    /**
     * Remove the specified object from the range of text to which it
     * was attached, if any.  It is OK to remove an object that was never
     * attached in the first place.
     */
    public void removeSpan(Object what);

    /**
     * Remove the specified object from the range of text to which it
     * was attached, if any.  It is OK to remove an object that was never
     * attached in the first place.
     *
     * See {@link Spanned} for an explanation of what the flags mean.
     *
     * @hide
     */
    default void removeSpan(Object what, int flags) {
        removeSpan(what);
    }

    /**
     * Factory used by TextView to create new {@link Spannable Spannables}. You can subclass
     * it to provide something other than {@link SpannableString}.
     *
     * @see android.widget.TextView#setSpannableFactory(Factory)
     */
    public static class Factory {
        private static Spannable.Factory sInstance = new Spannable.Factory();

        /**
         * Returns the standard Spannable Factory.
         */
        public static Spannable.Factory getInstance() {
            return sInstance;
        }

        /**
         * Returns a new SpannableString from the specified CharSequence.
         * You can override this to provide a different kind of Spannable.
         */
        public Spannable newSpannable(CharSequence source) {
            return new SpannableString(source);
        }
    }
}

Editable

静态单例 实现工厂方法 返回的SpannableStringBuilder,
This is the interface for text whose content and markup
can be changed

public interface Editable
extends CharSequence, GetChars, Spannable, Appendable
{
    /**
     * Replaces the specified range (st…en) of text in this
     * Editable with a copy of the slice start…end from
     * source.  The destination slice may be empty, in which case
     * the operation is an insertion, or the source slice may be empty,
     * in which case the operation is a deletion.
     * 

* Before the change is committed, each filter that was set with * {@link #setFilters} is given the opportunity to modify the * source text. *

* If source * is Spanned, the spans from it are preserved into the Editable. * Existing spans within the Editable that entirely cover the replaced * range are retained, but any that were strictly within the range * that was replaced are removed. If the source contains a span * with {@link Spanned#SPAN_PARAGRAPH} flag, and it does not satisfy the * paragraph boundary constraint, it is not retained. As a special case, the * cursor position is preserved even when the entire range where it is located * is replaced. * @return a reference to this object. * * @see Spanned#SPAN_PARAGRAPH */ public Editable replace(int st, int en, CharSequence source, int start, int end); /** * Convenience for replace(st, en, text, 0, text.length()) * @see #replace(int, int, CharSequence, int, int) */ public Editable replace(int st, int en, CharSequence text); /** * Convenience for replace(where, where, text, start, end) * @see #replace(int, int, CharSequence, int, int) */ public Editable insert(int where, CharSequence text, int start, int end); /** * Convenience for replace(where, where, text, 0, text.length()); * @see #replace(int, int, CharSequence, int, int) */ public Editable insert(int where, CharSequence text); /** * Convenience for replace(st, en, "", 0, 0) * @see #replace(int, int, CharSequence, int, int) */ public Editable delete(int st, int en); /** * Convenience for replace(length(), length(), text, 0, text.length()) * @see #replace(int, int, CharSequence, int, int) */ public Editable append(CharSequence text); /** * Convenience for replace(length(), length(), text, start, end) * @see #replace(int, int, CharSequence, int, int) */ public Editable append(CharSequence text, int start, int end); /** * Convenience for append(String.valueOf(text)). * @see #replace(int, int, CharSequence, int, int) */ public Editable append(char text); /** * Convenience for replace(0, length(), "", 0, 0). * Note that this clears the text, not the spans; * use {@link #clearSpans} if you need that. * @see #replace(int, int, CharSequence, int, int) */ public void clear(); /** * Removes all spans from the Editable, as if by calling * {@link #removeSpan} on each of them. */ public void clearSpans(); /** * Sets the series of filters that will be called in succession * whenever the text of this Editable is changed, each of which has * the opportunity to limit or transform the text that is being inserted. */ public void setFilters(InputFilter[] filters); /** * Returns the array of input filters that are currently applied * to changes to this Editable. */ public InputFilter[] getFilters(); /** * Factory used by TextView to create new {@link Editable Editables}. You can subclass * it to provide something other than {@link SpannableStringBuilder}. * * @see android.widget.TextView#setEditableFactory(Factory) */ public static class Factory { private static Editable.Factory sInstance = new Editable.Factory(); /** * Returns the standard Editable Factory. */ public static Editable.Factory getInstance() { return sInstance; } /** * Returns a new SpannedStringBuilder from the specified * CharSequence. You can override this to provide * a different kind of Spanned. */ public Editable newEditable(CharSequence source) { return new SpannableStringBuilder(source); } } }

object what 各种设置

1 AbsoluteSizeSpan 修改字体大小
//A span that changes the size of the text it's attached to.
public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {

    /**
     * Set the text size to size physical pixels.
     */
    public AbsoluteSizeSpan(int size) {
        this(size, false);
    }

    /**
     * Set the text size to size physical pixels, or to size
     * device-independent pixels if dip is true.
     */
    public AbsoluteSizeSpan(int size, boolean dip) {
        mSize = size;
        mDip = dip;
    }

    /**
     * Creates an {@link AbsoluteSizeSpan} from a parcel.
     */
    public AbsoluteSizeSpan(@NonNull Parcel src) {
        mSize = src.readInt();
        mDip = src.readInt() != 0;
    }

}

2 BackgroundColorSpan 修改背景色

Changes the background color of the text to which the span is attached.

public class BackgroundColorSpan extends CharacterStyle
        implements UpdateAppearance, ParcelableSpan {


  /**
     * Creates a {@link BackgroundColorSpan} from a color integer.
     * 

* * @param color color integer that defines the background color * @see android.content.res.Resources#getColor(int, Resources.Theme) */ public BackgroundColorSpan(@ColorInt int color) { mColor = color; } /** * Creates a {@link BackgroundColorSpan} from a parcel. */ public BackgroundColorSpan(@NonNull Parcel src) { mColor = src.readInt(); } }

3 BulletSpan

A span which styles paragraphs as bullet points (respecting layout direction).
设置小圆点似的符号
BulletSpans must be attached from the first character to the last character of a single paragraph. otherwise the bullet point will not be displayed but the first paragraph encountered will have a leading margin.

public class BulletSpan implements LeadingMarginSpan, ParcelableSpan {

 // Bullet is slightly bigger to avoid aliasing artifacts on mdpi devices.
    private static final int STANDARD_BULLET_RADIUS = 4;
    public static final int STANDARD_GAP_WIDTH = 2;
    private static final int STANDARD_COLOR = 0;


    @Px
    private final int mGapWidth;
    @Px
    private final int mBulletRadius;
    private Path mBulletPath = null;
    @ColorInt
    private final int mColor;
    private final boolean mWantColor;

    /**
     * Creates a {@link BulletSpan} with the default values.
     */
    public BulletSpan() {
        this(STANDARD_GAP_WIDTH, STANDARD_COLOR, false, STANDARD_BULLET_RADIUS);
    }

    /**
     * Creates a {@link BulletSpan} based on a gap width
     *
     * @param gapWidth the distance, in pixels, between the bullet point and the paragraph.
     */
    public BulletSpan(int gapWidth) {
        this(gapWidth, STANDARD_COLOR, false, STANDARD_BULLET_RADIUS);
    }

    /**
     * Creates a {@link BulletSpan} based on a gap width and a color integer.
     *
     * @param gapWidth the distance, in pixels, between the bullet point and the paragraph.
     * @param color    the bullet point color, as a color integer
     * @see android.content.res.Resources#getColor(int, Resources.Theme)
     */
    public BulletSpan(int gapWidth, @ColorInt int color) {
        this(gapWidth, color, true, STANDARD_BULLET_RADIUS);
    }

    /**
     * Creates a {@link BulletSpan} based on a gap width and a color integer.
     *
     * @param gapWidth     the distance, in pixels, between the bullet point and the paragraph.
     * @param color        the bullet point color, as a color integer.
     * @param bulletRadius the radius of the bullet point, in pixels.
     * @see android.content.res.Resources#getColor(int, Resources.Theme)
     */
    public BulletSpan(int gapWidth, @ColorInt int color, @IntRange(from = 0) int bulletRadius) {
        this(gapWidth, color, true, bulletRadius);
    }

    private BulletSpan(int gapWidth, @ColorInt int color, boolean wantColor,
            @IntRange(from = 0) int bulletRadius) {
        mGapWidth = gapWidth;
        mBulletRadius = bulletRadius;
        mColor = color;
        mWantColor = wantColor;
    }

    /**
     * Creates a {@link BulletSpan} from a parcel.
     */
    public BulletSpan(@NonNull Parcel src) {
        mGapWidth = src.readInt();
        mWantColor = src.readInt() != 0;
        mColor = src.readInt();
        mBulletRadius = src.readInt();
    }

}

4 ForegroundColorSpan 设置文字的颜色

Changes the color of the text to which the span is attached.

SpannableString string = new SpannableString("Text with a foreground color span");
string.setSpan(new ForegroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
5 LeadingMarginSpan.Standard 缩进
6 QuoteSpan 文本左侧添加一条竖线
SpannableString string = new SpannableString("Text with quote span on a long line");
 string.setSpan(new QuoteSpan(Color.GREEN, 20, 40), 0, string.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

A span which styles paragraphs by adding a vertical stripe at the beginning of the text (respecting layout direction).

A QuoteSpan must be attached from the first character to the last character of a single paragraph, otherwise the span will not be displayed.

public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan {

public QuoteSpan() {
        this(STANDARD_COLOR, STANDARD_STRIPE_WIDTH_PX, STANDARD_GAP_WIDTH_PX);
    }

 public QuoteSpan(@ColorInt int color) {
        this(color, STANDARD_STRIPE_WIDTH_PX, STANDARD_GAP_WIDTH_PX);
    }

  public QuoteSpan(@ColorInt int color, @IntRange(from = 0) int stripeWidth,
            @IntRange(from = 0) int gapWidth) {
        mColor = color;
        mStripeWidth = stripeWidth;
        mGapWidth = gapWidth;
    }

    public QuoteSpan(@NonNull Parcel src) {
        mColor = src.readInt();
        mStripeWidth = src.readInt();
        mGapWidth = src.readInt();
    }

}
7 RelativeSizeSpan 相对当前文本大小进行比例缩放

Uniformly scales the size of the text to which it's attached by a certain proportion.

SpannableString string = new SpannableString("Text with relative size span");
string.setSpan(new RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableSpan {

  /**
     * Creates a {@link RelativeSizeSpan} based on a proportion.
     *
     * @param proportion the proportion with which the text is scaled.
     */
    public RelativeSizeSpan(@FloatRange(from = 0) float proportion) {
        mProportion = proportion;
    }

    /**
     * Creates a {@link RelativeSizeSpan} from a parcel.
     */
    public RelativeSizeSpan(@NonNull Parcel src) {
        mProportion = src.readFloat();
    }
}
8 ScaleXSpan 字体按比例水平方向缩放

Scales horizontally the size of the text to which it's attached by a certain factor.

Values > 1.0 will stretch the text wider. Values < 1.0 will stretch the text narrower.

SpannableString string = new SpannableString("Text with ScaleX span");
 string.setSpan(new ScaleXSpan(2f), 10, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
9 StrikethroughSpan 给对应的文本加入删除线

A span that strikes through the text it's attached to.

SpannableString string = new SpannableString("Text with strikethrough span");

string.setSpan(new StrikethroughSpan(), 10, 23, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
10 StyleSpan 字体的样式

Span that allows setting the style of the text it's attached to.

Possible styles are: {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC} and
{@link Typeface#BOLD_ITALIC}.

SpannableString string = new SpannableString("Bold and italic text");

string.setSpan(new StyleSpan(Typeface.BOLD), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
string.setSpan(new StyleSpan(Typeface.ITALIC), 9, 15, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

11 SubscriptSpan 下标式的样式

The span that moves the position of the text baseline lower.

 SpannableString string = new SpannableString("☕- C8H10N4O2\n");
        string.setSpan(new SubscriptSpan(), 4, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        string.setSpan(new SubscriptSpan(), 6, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        string.setSpan(new SubscriptSpan(), 9, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        string.setSpan(new SubscriptSpan(), 11, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

12 SuperscriptSpan 上标样式

The span that moves the position of the text baseline higher.

SpannableString string = new SpannableString("1st example");
string.setSpan(new SuperscriptSpan(), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

12 TypefaceSpan 设置不同的字体

Span that updates the typeface of the text it's attached to

       Typeface myTypeface = Typeface.create(ResourcesCompat.getFont(context, R.font.acme),Typeface.BOLD);

        SpannableString string = new SpannableString("Text with typeface span.");
        string.setSpan(new TypefaceSpan(myTypeface), 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        string.setSpan(new TypefaceSpan("sans-serif"), 10, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        string.setSpan(new TypefaceSpan("monospace"), 19, 22, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

13 UnderlineSpan 下划线

A span that underlines the text it's attached to.

SpannableString string = new SpannableString("Text with underline span");
        string.setSpan(new UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

14 URLSpan 通过系统浏览器打开链接

Implementation of the {@link ClickableSpan} that allows setting a url string. When selecting and clicking on the text to which the span is attached, the URLSpan will try to open the url, by launching an an Activity with an {@link Intent#ACTION_VIEW} intent.

  SpannableString string = new SpannableString("Text with a url span");
  string.setSpan(new URLSpan("http://www.baidu.com"), 12, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

URLSpan 实现部分源码

public class URLSpan extends ClickableSpan implements ParcelableSpan{

 private final String mURL;
 public URLSpan(String url) {
        mURL = url;
    }
 public URLSpan(@NonNull Parcel src) {
        mURL = src.readString();
    }


    @Override
    public void onClick(View widget) {
        Uri uri = Uri.parse(getURL());
        Context context = widget.getContext();
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
        }
    }

}

15 ClickableSpan 抽象类

If an object of this type is attached to the text of a TextView with a movement method of LinkMovementMethod, the affected spans of text can be selected. If selected and clicked, the {@link #onClick} method will be called.

也就是需要实现点击效果 必须
textView.setMovementMethod(LinkMovementMethod.getInstance());重写onClick.

支持下划线和颜色设置 重写 updateDrawState

public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {
    private static int sIdCounter = 0;

    private int mId = sIdCounter++;

    /**
     * Performs the click action associated with this span.
     */
    public abstract void onClick(@NonNull View widget);

    /**
     * Makes the text underlined and in the link color.
     */
    @Override
    public void updateDrawState(@NonNull TextPaint ds) {
        ds.setColor(ds.linkColor);
        ds.setUnderlineText(true);
    }

    /**
     * Get the unique ID for this span.
     *
     * @return The unique ID.
     * @hide
     */
    public int getId() {
        return mId;
    }
}
16 DrawableMarginSpan

A span which adds a drawable and a padding to the paragraph it's attached to.

If the height of the drawable is bigger than the height of the line it's attached to then the line height is increased to fit the drawable. DrawableMarginSpan allows setting a padding between the drawable and the text. The default value is 0. The span must be set from the beginning of the text, otherwise either the span won't be rendered or it will be rendered incorrectly.

SpannableString string = new SpannableString("Text with a drawable.");

string.setSpan(new DrawableMarginSpan(drawable, 20), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
17 IconMarginSpan

类似DrawableMarginSpan 只不过,不过是加入Bitmap

18 ImageSpan 图片样式,主要用于在文本中插入图片
19 MaskFilterSpan

Span that allows setting a {@link MaskFilter} to the text it's attached to.

文本滤镜 目前只有模糊效果 BlurMaskFilter 和浮雕效果EmbossMaskFilter

       MaskFilter blurMask = new BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL);
        SpannableString string = new SpannableString("Text with blur mask");

        string.setSpan(new MaskFilterSpan(blurMask), 10, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

你可能感兴趣的:(android 富文本设计)