Android Span 的使用

字体规格(Font Metrics)

  • 如果你想知道更多什么是字体规格,那么看下面的图解:
    Android Span 的使用_第1张图片

BulletSpan

  • android.text.style.BulletSpan
  • BulletSpan影响段落层次的文本格式。它可以给段落的开始处加上项目符号。

    /**
    * gapWidth:项目符号和文本之间的间隙
    * color: 项目符号的颜色,默认为透明
    */
    //创建一个黑色的BulletSpan,间隙为15px
    span = new BulletSpan(15, Color.BLACK);
    

Android Span 的使用_第2张图片

QuoteSpan

  • android.text.style.QuoteSpan
  • QuoteSpan影响段落层次的文本格式。它可以给一个段落加上垂直的引用线。

    /**
    * color: 垂直的引用线颜色,默认是蓝色
    */
    //创建一个红色的引用
    span = new QuoteSpan(Color.RED);
    

Android Span 的使用_第3张图片

QuoteSpan

  • android.text.style.AlignmentSpan.Standard
  • AlignmentSpan.Standard影响段落层次的文本格式。它可以把段落的每一行文本按正常、居中、相反的方式对齐。

    /**
    * align: 对齐方式
    */
    //居中对齐的段落
    span = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER);
    

Android Span 的使用_第4张图片

UnderlineSpan

  • android.text.style.UnderlineSpan
  • UnderlineSpan影响字符级的文本格式。它可以为字符集加上下划线,归功于Paint#setUnderlineText(true))。

    //下划线
    span = new UnderlineSpan();
    

Android Span 的使用_第5张图片

StrikethroughSpan

  • android.text.style.StrikethroughSpan
  • StrikethroughSpan影响字符级的文本格式。它可以给字符集加上删除线,归功于Paint#setStrikeThruText(true))。

    //删除线
    span = new StrikethroughSpan();
    

Android Span 的使用_第6张图片

SubscriptSpan

  • android.text.style.SubscriptSpan
  • SubscriptSpan影响字符级的文本格式,它可以通过减小TextPaint#baselineShift给字符集加下标。

    //下标
    span = new SubscriptSpan();
    

Android Span 的使用_第7张图片

BackgroundColorSpan

  • android.text.style.BackgroundColorSpan
  • BackgroundColorSpan影响字符级的文本格式。它可以给字符集加上背景颜色。

    /**
    * color: 背景颜色
    */
    //设置字符背景颜色
    span = new BackgroundColorSpan(Color.GREEN);
    

Android Span 的使用_第8张图片

ForegroundColorSpan

  • android.text.style.ForegroundColorSpan
  • ForegroundColorSpan影响字符级的文本格式,它可以设置字符集的前景颜色也即文字颜色。

    /**
    * color: 前景颜色
    */
    //设置红色的前景
    span = new ForegroundColorSpan(Color.RED);
    

Android Span 的使用_第9张图片

ImageSpan

  • android.text.style.ImageSpan
  • ImageSpan影响字符级的文本格式。它可以生成图像字符。这是为数不多的文档齐全的Span所以enjoy it!

    /**
    * Context: 上下文
    * resourceId: 图像资源id
    */
    //用一个小图像代替字符
    span = new ImageSpan(this, R.drawable.pic1_small);
    

Android Span 的使用_第10张图片

StyleSpan

  • android.text.style.StyleSpan
  • StyleSpan影响字符级的文本格式,它可以给字符集设置样式(blod、italic、normal)。

    //设置bold+italic的字符样式
    span = new StyleSpan(Typeface.BOLD | Typeface.ITALIC);
    

Android Span 的使用_第11张图片

TypefaceSpan

  • android.text.style.TypefaceSpan
  • TypefaceSpan影响字符级的文本格式。它可以给字符设置字体集(monospace、serif等)。

    //设置serif family
    span = new TypefaceSpan("serif");
    

Android Span 的使用_第12张图片

TextAppearanceSpan

  • android.text.style.TextAppearanceSpan
  • TextAppearanceSpan影响字符级的文本格式。它可以给字符集设置外观(appearance)。

    /**
    * TextAppearanceSpan(Context context, int appearance, int colorList)
    *                     context: 上下文
    *                     appearance:appearance资源id(例如:android.R.style.TextAppearance_Small)
    *                     colorList:文本的颜色资源id(例如:android.R.styleable.Theme_textColorPrimary)
    *
    * TextAppearanceSpan(String family, int style, int size, ColorStateList color, ColorStateList linkColor)
    * family:字体family
    * style:描述样式(例如:android.graphics.Typeface)
    * size:文字大小
    * color:文字颜色
    * linkColor:连接文本的颜色
    */
    //设置serif family
    span = new TextAppearanceSpan(this/*a context*/, R.style.SpecialTextAppearance);
    <-- style.xml -->
    
    

Android Span 的使用_第13张图片

AbsoluteSizeSpan

  • android.text.style.AbsoluteSizeSpan
  • AbsoluteSizeSpan影响字符级的文本格式。它可以设置一个字符集的绝对文字大小。

    /**
    * size: 大小
    * dip: false,size单位为px,true,size单位为dip(默认为false)。
    */
    //设置文字大小为24dp
    span = new AbsoluteSizeSpan(24, true);
    

Android Span 的使用_第14张图片

RelativeSizeSpan

  • android.text.style.RelativeSizeSpan
  • RelativeSizeSpan影响字符水平的文本格式。它可以设置字符集的文本大小。

    //设置文字大小为大2倍
    span = new RelativeSizeSpan(2.0f);
    

Android Span 的使用_第15张图片

ScaleXSpan

  • android.text.style.ScaleXSpan
  • ScaleXSpan印象字符集的文本格式。它可以在x轴方向上缩放字符集。

    //设置水平方向上放大3倍
    span = new ScaleXSpan(3.0f);
    

Android Span 的使用_第16张图片

MaskFilterSpan

  • android.text.style.MaskFilterSpan
  • MaskFilterSpan影响字符集文本格式。它可以给字符集设置android.graphics.MaskFilter。
  • 警告:BlurMaskFilter不支持硬件加速

    //模糊字符集
    span = new MaskFilterSpan(new BlurMaskFilter(density*2, BlurMaskFilter.Blur.NORMAL));
    //浮雕字符集
    span = new MaskFilterSpan(new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f));
    
  • MaskFilterSpan的效果图: BlurMaskFilter

Android Span 的使用_第17张图片

  • MaskFilterSpan的效果图: EmbossMaskFilter

Android Span 的使用_第18张图片

Spans进阶

  • 前景色(文字颜色)动画

Android Span 的使用_第19张图片

  • 前景色(文字颜色)动画
  • ForegroundColorSpan为只读。这意味实例化之后着你不能改变你不能改变前景色。所以,要做的第一件事就是编写一个MutableForegroundColorSpan。(不固定的)

  • MutableForegroundColorSpan.java

    public class MutableForegroundColorSpan extends ForegroundColorSpan {
        private int mAlpha = 255;
        private int mForegroundColor;
        public MutableForegroundColorSpan(int alpha, int color)
        {
            super(color);
            mAlpha = alpha;
            mForegroundColor = color;
        }
        public MutableForegroundColorSpan(Parcel src)
        {
            super(src);
            mForegroundColor = src.readInt();
            mAlpha = src.readInt();
        }
        public void writeToParcel(Parcel dest, int flags)
        {
            super.writeToParcel(dest, flags);
            dest.writeInt(mForegroundColor);
            dest.writeFloat(mAlpha);
        }
        @Override
        public void updateDrawState(TextPaint ds)
        {
            ds.setColor(getForegroundColor());
        }
        /**
        * @param alpha from 0 to 255
        */
        public void setAlpha(int alpha)
        {
            mAlpha = alpha;
        }
        public void setForegroundColor(int foregroundColor)
        {
            mForegroundColor = foregroundColor;
        }
        public float getAlpha()
        {
            return mAlpha;
        }
        @Override
        public int getForegroundColor()
        {
            return Color.argb(mAlpha, Color.red(mForegroundColor), Color.green(mForegroundColor), Color.blue(mForegroundColor));
        }
    }
    
  • 现在,我们可以在同一个实例改变透明度和前景色了。但是,当你设置这些属性,它并不会刷新视图,你必须通过重新设置SpannableString才能刷新视图。

    MutableForegroundColorSpan span = new MutableForegroundColorSpan(255, Color.BLACK);
    spannableString.setSpan(span, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    textView.setText(spannableString);
    //黑色完全不透明(译者注:上面代码的效果)
    span.setAlpha(100);
    span.setForegroundColor(Color.RED);
    //到这一步文字没有变化
    textView.setText(spannableString);
    //最后,文字变为红色和透明
    
  • 现在我们要前景色的动画。我们可以自定义android.util.Property。

    private static final Property MUTABLE_FOREGROUND_COLOR_SPAN_FC_PROPERTY =
    new Property(Integer.class, "MUTABLE_FOREGROUND_COLOR_SPAN_FC_PROPERTY") {
        @Override
        public void set(MutableForegroundColorSpan span, Integer value) {
            span.setForegroundColor(value);
        }
        @Override
        public Integer get(MutableForegroundColorSpan span) {
            return span.getForegroundColor();
        }
    };
    
  • 最后,我们使用属性动画(ObjectAnimator)让自定义属性动起来。不要忘记更新视图。

    MutableForegroundColorSpan span = new MutableForegroundColorSpan(255, Color.BLACK);
    mSpannableString.setSpan(span, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    ObjectAnimator objectAnimator = ObjectAnimator.ofInt(span, MUTABLE_FOREGROUND_COLOR_SPAN_FC_PROPERTY, Color.BLACK, Color.RED);
    objectAnimator.setEvaluator(new ArgbEvaluator());
    objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            //refresh
            mText.setText(mSpannableString);
        }
    });
    objectAnimator.start();
    

ActionBar”烟火”

image

  • “烟 火”动画是让文字随机淡入。首先,把文字切断成多个spans(例如,一个character的span),淡入spans后再淡入其它的spans。用前面介绍的MutableForegroundColorSpan,我们将创建一组特殊的span对象。在span组调用对应的setAlpha方法,我们随机设置每个span的透明度。

    private static final class FireworksSpanGroup {
        private final float mAlpha;
        private final ArrayList mSpans;
        private FireworksSpanGroup(float alpha) {
            mAlpha = alpha;
            mSpans = new ArrayList();
        }
        public void addSpan(MutableForegroundColorSpan span) {
            span.setAlpha((int) (mAlpha * 255));
            mSpans.add(span);
        }
        public void init() {
            Collections.shuffle(mSpans);
        }
        public void setAlpha(float alpha) {
            int size = mSpans.size();
            float total = 1.0f * size * alpha;
            for(int index = 0 ; index < size; index++) {
                MutableForegroundColorSpan span = mSpans.get(index);
                if(total >= 1.0f) {
                    span.setAlpha(255);
                    total -= 1.0f;
                } else {
                    span.setAlpha((int) (total * 255));
                    total = 0.0f;
                }
            }
        }
        public float getAlpha() { return mAlpha; }
    }
    
  • 我们创建一个自定义属性动画的属性去更改FireworksSpanGroup的透明度

    private static final Property FIREWORKS_GROUP_PROGRESS_PROPERTY =
    new Property(Float.class, "FIREWORKS_GROUP_PROGRESS_PROPERTY") {
        @Override
        public void set(FireworksSpanGroup spanGroup, Float value) {
            spanGroup.setProgress(value);
        }
        @Override
        public Float get(FireworksSpanGroup spanGroup) {
            return spanGroup.getProgress();
        }
    };
    
  • 最后,我们创建span组并使用一个ObjectAnimator给其加上动画。

    final FireworksSpanGroup spanGroup = new FireworksSpanGroup();
    //初始化包含多个spans的grop
    //spanGroup.addSpan(span);
    //给ActionBar的标题设置spans
    //mActionBarTitleSpannableString.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    spanGroup.init();
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(spanGroup, FIREWORKS_GROUP_PROGRESS_PROPERTY, 0.0f, 1.0f);
    objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            //更新标题
            setTitle(mActionBarTitleSpannableString);
        }
    });
    objectAnimator.start();
    

使用自定义的span

  • 在本节中,我们将看到使用自定义span来绘制的方式。这是文本定制很好的方式。
  • 首先,我们要创建一个继承ReplacementSpan抽象类的自定义Span。
    如果你想画一个自定义的背景,你可以实现LineBackgroundSpan
    ,这是影响段落级的文本格式。

  • 我们必须实现2个方法:

    getSize):这个方法返回新的你更换后的size。
    text:Span管理的文本
    start:文本开始处
    end:文本结尾处
    fm:字体规格,可以为空
    draw):可以使用Canvas绘制。
    x:绘制文本的x坐标
    top:线(line)的顶部(译者注:line的定义参看前面字体规格这一节)
    y:基线
    bottom:线的底部、
    
  • 让我们看一个例子,画一个包围文本的蓝色矩形。

    FrameSpan.java
    
    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm)
    {
        //将返回相对于Paint画笔的文本
        mWidth = (int) paint.measureText(text, start, end);
        return mWidth;
    }
    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)
    {
        //使用自定义的画笔绘制在画布上
        canvas.drawRect(x, top, x + mWidth, bottom, mPaint);
    }
    

Android Span 的使用_第20张图片

附加

  • Sample app包含了一些Spans进阶的例子,如下:

    • Progressive blur

    Android Span 的使用_第21张图片

    • Typewriter

    Android Span 的使用_第22张图片

你可能感兴趣的:(android)