美文网首页Android日记andnroidAndroid_UI
我赌5毛你没见过这样的SpannableString

我赌5毛你没见过这样的SpannableString

作者: Blankj | 来源:发表于2017-06-11 22:51 被阅读11511次

Foreword

本文不是标题党哈,进来的肯定会有收获,啥也不说,先来个gif把5毛钱收起来再说。

anim_span.gif

其次是静态的。

span.png

不要小看哦,上面两张图的效果我只用了两个TextView,其实一个TextView也可以完成,但是考虑到动静可以分开来优化内存,所以动态图用了一个TextView,静态图用了一个TextView。好了,看也看完了,我是不赌赢了哈。

Introduce

我们先来分析静态图的,从标题SpanUtils可以看出,我已经为你们封装好了相关工具类,该工具类就可以为你快速创建出上图中的任一样式。Talk is cheap. Let me show the code for u.

tvAboutSpan.setText(new SpanUtils()
        .appendLine("SpanUtils").setBackgroundColor(Color.LTGRAY).setBold().setForegroundColor(Color.YELLOW).setAlign(Layout.Alignment.ALIGN_CENTER)
        .appendLine("前景色").setForegroundColor(Color.GREEN)
        .appendLine("背景色").setBackgroundColor(Color.LTGRAY)
        .appendLine("行高顶部对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_TOP).setBackgroundColor(Color.GREEN)
        .appendLine("行高居中对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_CENTER).setBackgroundColor(Color.LTGRAY)
        .appendLine("行高底部对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_BOTTOM).setBackgroundColor(Color.GREEN)
        .appendLine("测试段落缩,首行缩进两字,其他行不缩进").setLeadingMargin((int) textSize * 2, 10).setBackgroundColor(Color.GREEN)
        .appendLine("测试引用,后面的字是为了凑到两行的效果").setQuoteColor(Color.GREEN, 10, 10).setBackgroundColor(Color.LTGRAY)
        .appendLine("测试列表项,后面的字是为了凑到两行的效果").setBullet(Color.GREEN, 20, 10).setBackgroundColor(Color.LTGRAY).setBackgroundColor(Color.GREEN)
        .appendLine("测试图标文字顶部对齐,后面的字是为了凑到两行的效果").setIconMargin(R.drawable.shape_spannable_block_high, 20, SpanUtils.ALIGN_TOP).setBackgroundColor(Color.LTGRAY)
        .appendLine("测试图标文字居中对齐,后面的字是为了凑到两行的效果").setIconMargin(R.drawable.shape_spannable_block_high, 20, SpanUtils.ALIGN_CENTER).setBackgroundColor(Color.GREEN)
        .appendLine("测试图标文字底部对齐,后面的字是为了凑到两行的效果").setIconMargin(R.drawable.shape_spannable_block_high, 20, SpanUtils.ALIGN_BOTTOM).setBackgroundColor(Color.LTGRAY)
        .appendLine("测试图标顶部对齐,后面的字是为了凑到两行的效果").setIconMargin(R.drawable.shape_spannable_block_low, 20, SpanUtils.ALIGN_TOP).setBackgroundColor(Color.GREEN)
        .appendLine("测试图标居中对齐,后面的字是为了凑到两行的效果").setIconMargin(R.drawable.shape_spannable_block_low, 20, SpanUtils.ALIGN_CENTER).setBackgroundColor(Color.LTGRAY)
        .appendLine("测试图标底部对齐,后面的字是为了凑到两行的效果").setIconMargin(R.drawable.shape_spannable_block_low, 20, SpanUtils.ALIGN_BOTTOM).setBackgroundColor(Color.GREEN)
        .appendLine("32dp字体").setFontSize(32, true)
        .appendLine("2倍字体").setFontProportion(2)
        .appendLine("横向2倍字体").setFontXProportion(1.5f)
        .appendLine("删除线").setStrikethrough()
        .appendLine("下划线").setUnderline()
        .append("测试").appendLine("上标").setSuperscript()
        .append("测试").appendLine("下标").setSubscript()
        .appendLine("粗体").setBold()
        .appendLine("斜体").setItalic()
        .appendLine("粗斜体").setBoldItalic()
        .appendLine("monospace字体").setFontFamily("monospace")
        .appendLine("自定义字体").setTypeface(Typeface.createFromAsset(getAssets(), "fonts/dnmbhs.ttf"))
        .appendLine("相反对齐").setAlign(Layout.Alignment.ALIGN_OPPOSITE)
        .appendLine("居中对齐").setAlign(Layout.Alignment.ALIGN_CENTER)
        .appendLine("正常对齐").setAlign(Layout.Alignment.ALIGN_NORMAL)
        .append("测试").appendLine("点击事件").setClickSpan(clickableSpan)
        .append("测试").appendLine("Url").setUrl("https://github.com/Blankj/AndroidUtilCode")
        .append("测试").appendLine("模糊").setBlur(3, BlurMaskFilter.Blur.NORMAL)
        .appendLine("颜色渐变").setShader(new LinearGradient(0, 0,
                64 * density * 4, 0,
                getResources().getIntArray(R.array.rainbow),
                null,
                Shader.TileMode.REPEAT)).setFontSize(64, true)
        .appendLine("图片着色").setFontSize(64, true).setShader(new BitmapShader(ImageUtils.getBitmap(R.drawable.cheetah),
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT))
        .appendLine("阴影效果").setFontSize(64, true).setBackgroundColor(Color.BLACK).setShadow(24, 8, 8, Color.WHITE)
        .append("测试小图对齐").setBackgroundColor(Color.LTGRAY)
        .appendImage(R.drawable.shape_spannable_block_low, SpanUtils.ALIGN_TOP)
        .appendImage(R.drawable.shape_spannable_block_low, SpanUtils.ALIGN_CENTER)
        .appendImage(R.drawable.shape_spannable_block_low, SpanUtils.ALIGN_BASELINE)
        .appendImage(R.drawable.shape_spannable_block_low, SpanUtils.ALIGN_BOTTOM)
        .appendLine("end").setBackgroundColor(Color.LTGRAY)
        .append("测试大图字体顶部对齐").setBackgroundColor(Color.GREEN)
        .appendImage(R.drawable.shape_spannable_block_high, SpanUtils.ALIGN_TOP)
        .appendLine()
        .append("测试大图字体居中对齐").setBackgroundColor(Color.LTGRAY)
        .appendImage(R.drawable.shape_spannable_block_high, SpanUtils.ALIGN_CENTER)
        .appendLine()
        .append("测试大图字体底部对齐").setBackgroundColor(Color.GREEN)
        .appendImage(R.drawable.shape_spannable_block_high, SpanUtils.ALIGN_BOTTOM)
        .appendLine()
        .append("测试空格").appendSpace(30, Color.LTGRAY).appendSpace(50, Color.GREEN).appendSpace(100).appendSpace(30, Color.LTGRAY).appendSpace(50, Color.GREEN)
        .create());

可能有些小伙伴看过我曾经的一篇文章(工具类之SpannableStringUtils(相信你会爱上它)),没错,如今SpannableStringUtils已升级为SpanUtils,它拥有更多、更完善的设置,为了弥补这些曾经所没有的,柯基真是费了好大力气才实现了这些,比如设置图片的对齐方式,设置行高对齐方式,设置图标对齐方式等的设置,当然中间也有失败的,比如我做不到在原有样式基础上给局部文字加边框,这我真的没辙。如果我设计的这么多span都满足不了大佬们的需求,那大佬们可以自定义实现span,最终调用SpanUtils.setSpans(xxxSpan)即可,这样就完美解决了其狭隘性。

有小伙伴肯定好奇动图是怎么实现的,其实只需要一个属性动画的值来控制SpannableString的属性即可,献上源代码供大佬们参阅。

private void initAnimSpan() {
    mShaderWidth = 64 * density * 4;
    mShader = new LinearGradient(0, 0,
            mShaderWidth, 0,
            getResources().getIntArray(R.array.rainbow),
            null,
            Shader.TileMode.REPEAT);
    matrix = new Matrix();

    mBlurMaskFilterSpan = new BlurMaskFilterSpan(25);

    mShadowSpan = new ShadowSpan(8, 8, 8, Color.WHITE);

    mForegroundAlphaColorSpan = new ForegroundAlphaColorSpan(Color.TRANSPARENT);

    mForegroundAlphaColorSpanGroup = new ForegroundAlphaColorSpanGroup(0);

    mPrinterString = "打印动画,后面的文字是为了测试打印效果...";

    mSpanUtils = new SpanUtils()
            .appendLine("彩虹动画").setFontSize(64, true).setShader(mShader)
            .appendLine("模糊动画").setFontSize(64, true).setSpans(mBlurMaskFilterSpan)
            .appendLine("阴影动画").setFontSize(64, true).setBackgroundColor(Color.BLACK).setSpans(mShadowSpan)
            .appendLine("透明动画").setFontSize(64, true).setSpans(mForegroundAlphaColorSpan);
    for (int i = 0, len = mPrinterString.length(); i < len; ++i) {
        ForegroundAlphaColorSpan span = new ForegroundAlphaColorSpan(Color.TRANSPARENT);
        mSpanUtils.append(mPrinterString.substring(i, i + 1)).setSpans(span);
        mForegroundAlphaColorSpanGroup.addSpan(span);
    }
    animSsb = mSpanUtils.create();
}

private void startAnim() {
    valueAnimator = ValueAnimator.ofFloat(0, 1);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // shader
            matrix.reset();
            matrix.setTranslate((Float) animation.getAnimatedValue() * mShaderWidth, 0);
            mShader.setLocalMatrix(matrix);

            // blur
            mBlurMaskFilterSpan.setRadius(25 * (1.00001f - (Float) animation.getAnimatedValue()));

            // shadow
            mShadowSpan.setDx(16 * (0.5f - (Float) animation.getAnimatedValue()));
            mShadowSpan.setDy(16 * (0.5f - (Float) animation.getAnimatedValue()));

            // alpha
            mForegroundAlphaColorSpan.setAlpha((int) (255 * (Float) animation.getAnimatedValue()));

            // printer
            mForegroundAlphaColorSpanGroup.setAlpha((Float) animation.getAnimatedValue());

            // update
            tvAboutAnimRainbow.setText(animSsb);
        }
    });

    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.setDuration(600 * 3);
    valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
    valueAnimator.start();
}

有个小细节需要注意,当用到模糊相关的操作,最好关闭view的硬件加速,否则会遇到奇怪的现象哦。

相关demo的代码说得差不多了,下面我就来介绍一下SpanUtils,其使用了建造者模式,内部用的是SpannableStringBuilder来拼接多个SpannableString,每次appendXXX都会拼接上一次的SpannableString,最终create便返回其SpannableStringBuilder实例,具体API如下所示。

API

SpannableString相关→SpanUtils.javaDemo

setFlag           : 设置标识
setForegroundColor: 设置前景色
setBackgroundColor: 设置背景色
setLineHeight     : 设置行高
setQuoteColor     : 设置引用线的颜色
setLeadingMargin  : 设置缩进
setBullet         : 设置列表标记
setIconMargin     : 设置图标
setFontSize       : 设置字体尺寸
setFontProportion : 设置字体比例
setFontXProportion: 设置字体横向比例
setStrikethrough  : 设置删除线
setUnderline      : 设置下划线
setSuperscript    : 设置上标
setSubscript      : 设置下标
setBold           : 设置粗体
setItalic         : 设置斜体
setBoldItalic     : 设置粗斜体
setFontFamily     : 设置字体系列
setTypeface       : 设置字体
setAlign          : 设置对齐
setClickSpan      : 设置点击事件
setUrl            : 设置超链接
setBlur           : 设置模糊
setShader         : 设置着色器
setShadow         : 设置阴影
setSpans          : 设置样式
append            : 追加样式字符串
appendLine        : 追加一行样式字符串
appendImage       : 追加图片
appendSpace       : 追加空白
create            : 创建样式字符串

Conclusion

其源码我就不粘贴上来了,毕竟有1500多行,比较占空间,有兴趣的大佬可以去了解一下,如果使用上有问题欢迎到我GitHubAndroid开发人员不得不收集的代码(持续更新中)提issue,好了,本工具类到此结束,为柯基砸上你们的喜欢吧(臭不要脸)。

相关文章

  • Snackbar和Toast的花式使用,这一篇就够了

    Foreword 这一篇是建立在我赌5毛你没见过这样的SpannableString基础上的,所以不会使用Span...

  • 我赌5毛你没见过这样的SpannableString

    Foreword 本文不是标题党哈,进来的肯定会有收获,啥也不说,先来个gif把5毛钱收起来再说。 其次是静态的。...

  • 让代码说话!

    原文 Let the code speak! 你见过这样的代码么: 我赌你见过(或者以后会见到)。类似的代码存在于...

  • 这样的“傻子”你见过没

    之前空调遥控器不是生病了么?找到病因是电池的问题,可拆了东墙补西墙,东墙也还是要还原啊… 于是到沃尔玛购物准备顺便...

  • 这样的姐妹仨,你见过没?

    说来好笑,我们四姐妹,除了我们大姐外,其他姐妹仨都不会煮饭,不信?你就接着往下看吧。 在我们老家,正月有宴请亲朋好...

  • 我赌五毛你没见过这样的游记!

    浊者不清工作室 原创 小爱同学 奇怪的旅行者 嘘~我要告诉你一个秘密…… 一、痛 今天是会吃人的衣服…… 我已经记...

  • Android SpannableString用法

    SpannableString 什么是SpannableString?SpannableString,是CharS...

  • Span

    SpannableString 和 SpannableStringBuilder SpannableString不...

  • 没有人告诉你的却是事实三

    1.荷兰中国游客无素质旅游与他国节目诽谤辱华形成反差,都说见过你这样没素质的世界真没见过你这样没素质的,自己的素质...

  • 虚实

    真的梦到了 好甜好甜 已经忍住了四天没联系你 大概你也不会想我 更不会主动联系我 我就赌 和自己赌 赌我能忍住多少...

网友评论

  • Oort:大神,有个问题。那个模糊设置了好像会系统缓存样式。被模糊过的文字。在应用其他地方使用会自带模糊样式。
  • db41a0b4e64d:点击事件没有效果啊
    c3f1ada035f0:点击 事件没效果,而且设置点击事件字体的颜色自动变了
  • Speronie:大神,有个疑问,行高居中对齐对多行的文本能生效吗?为什么我试的时候,除了第一行那段文字可以正常居中以外,后面的文字(第二行开始)直接就不显示了呢?
  • pdog18:demo挂了。。。
  • 南宫轩涵:点击事件怎么去掉有点击字符的下划线
    Blankj:@南宫轩涵 图片比字大还是小
    南宫轩涵:@Blankj 我看到了,但是中间添加图片还是不能居中
    Blankj:@南宫轩涵 ClickSpan里的ds.setUnderlineText(true);去掉就行
  • 老余的故事:哎呀,好,无敌的好:relaxed:
  • dabf8e02a0f4:来给大神点赞:+1: :+1: :+1:
  • ramblejoy:66666666666
  • 柴柴777:有点意思呀
  • 小新哥的大梦想:赞一个。。。。。。
  • ed6918f57426:第五行的变量lineHeight的值是多少?在哪声明?不止这一处变量没有,还有好多,请写清楚
    Blankj:@芥末末的沫 所以我主要写的就是使用方式哈,而不太在乎一些变量的赋值,具体Demo地址我也提供了,可以点击链接查看,源码也有相应的注释哈。
    芥末末的沫:@Blankj 一个工具库的介绍还是尽量的详细一点好啊,能够有API文档的那种写法就更好,毕竟不是几行代码就能实现的简单到一看就懂的东西。
    Blankj:@清风折柳 具体去看demo,分清主次,我只把重要的放上来了,次要的放上来浪费时间么不是
  • 大脑好饿:图片支持GIF图吗?
    路人丁Coco:@Blankj 楼主 我赌5毛 可以显示的 :yum:
    Blankj:@只是个昵称 你觉得TextView可以显示gif图吗
  • a98c05e99d6a:~\(≧▽≦)/~
  • 85289ad66c32:给大佬点个赞
  • 青蛙要fly:挺不错的
    Blankj:@青蛙要fly :sunglasses:
  • 95e44acf2b6d:楼主,五毛钱给我吧。这个种我也有。
    Blankj:@森眸暖光_369e :clap: :clap: :clap:
    95e44acf2b6d:@Blankj :sunglasses: 一大早就赚了五毛钱,想想还是很开心:kissing_heart:
    Blankj:@森眸暖光_369e 你这太不厚道了:angry:
  • 月有缘_d14c:挺好的:wink:
    Blankj:@月有缘_d14c :hushed: 不是应该相当好么:wink:
  • Alex_Cin:楼主好棒
    Blankj:@Alex_Cin 毕竟周一早上都会水一水
    Alex_Cin:@Blankj 遇到秒回的大神,我的内心是激动的
    Blankj:@Alex_Cin :sunglasses: 大家一起棒棒
  • yaoTongxue:学习了,长见识了,。多谢
    Blankj:@yaoTongxue 好好掌握基础知识,如果连群问题都回答不了,那你得好好补补自己的基础
    yaoTongxue:@Blankj QQ群输入it答案怎么错误呢。。嘻嘻,刚入道的小白,关注你了。。
    Blankj:@yaoTongxue :sunglasses:
  • 楊帥:赞
  • 9e07fa19e1ed:已经爱上他了
    Blankj:@jonenet0619 :smile:
  • 117fddfea130:赞一个
  • Xdjm:第一

本文标题:我赌5毛你没见过这样的SpannableString

本文链接:https://www.haomeiwen.com/subject/yiqkqxtx.html