「Efficient Android Threading 笔记」- C1 Android Components and the Need for Multiprocessing Android RecyclerView Android Socket Programming Supporting Multiple Screens Make a Reusable UI in Android App Development 如何在 Android Studio 中包含 *.so library,并使用库中定义的方法? 使用 SpannableString 格式化字符串,实现前景色、下划线、超链接、图文混排等 如何使用 bound service 完成进程间通信? 创建自定义视图 Creating custom views 通过 Android Theme & Style 定制应用的样式 「译」Android ViewPropertyAnimator 介绍 Android Animation Interpolator - Android 动画插值器源码笔记 「译」Android Animation in Honeycomb by Chet Haase(Android 3.0系统中的动画机制) 从 Android Sample ApiDemos 中学习 android.animation API 的用法 如何学习 Android Animation? 如何实现 Android ListView「上拉加载更多」? 「译」向Big Nerd Ranch提问:为什么Fragment在Android App开发中非常重要? 分类整理我在 SegmentFault 上针对某些问题作的回答 Android Servcie 后台服务总结笔记 如何在Android设备旋转时暂存数据以保护当前的交互状态? Android Message Handler 消息处理机制总结笔记 如何获取FragmentTabHost中指定标签页的Fragment? Fragment子类必须包含一个public无参构造器 如何更新及替换ViewPager中的Fragment? 如何使用Android UI Fragment开发“列表-详情”界面? 一个Android音频文本同步的英文有声读物App的开发过程 「Android编程权威指南笔记」Android应用本地化 通过jfeinstein10/SlidingMenu实现Android侧滑菜单 为Ubuntu14.04部署Android App的Eclipse开发环境 「Android编程权威指南笔记」使用ListFragment显示列表 「Android编程权威指南笔记」SDK版本与兼容 「Android编程权威指南笔记」Android布局和组件 「Android编程权威指南笔记」UI Fragment 「Android编程权威指南笔记」Activity 第一次开发iOS App和Android的对比总结笔记 「App Training笔记」创建第一个应用 「App Training笔记」开发入门训练大纲 Android APP - 从远程FTP服务器下载文件到本地

使用 SpannableString 格式化字符串,实现前景色、下划线、超链接、图文混排等

2016年03月28日

格式化字符串的工具类 SpannableStringBuilder

为了格式化字符串,可以使用 SpannableStringBuilder
SpannableStringBuilder 有一个方法 setSpan (Object what, int start, int end, int flags),可以把由 start 和 end 指定的部分字符串替换成给定的对象,给定的对象可以是:

  • ForegroundColorSpan 添加前景色;
  • BackgroundColorSpan 添加背景色;
  • RelativeSizeSpan 改变文字的相对大小;
  • StyleSpan 粗体、斜体等样式;
  • UnderlineSpan 添加下划线;
  • StrikethroughSpan 添加删除线;
  • SuperscriptSpan 上标;
  • SubscriptSpan 下标;
  • ClickableSpan 添加 URL 超链接样式;
  • ImageSpan 添加图片到字符串,实现图文混排(How to add image to text in TextView);
  • 这些 span 继承(或间接继承)自 CharacterStyle

效果如下图:

demo

ImageSpan: 调整图片大小,使图片和 TextView 高度一致

添加 drawable 时,必须动态的获取 TextView 高度,然后调用 drawable.set(left, top, right, bottom) 设置 drawable 大小,否则 drawable 和 string 高度不一致,会很难看。
而一般情况下,TextView 的高度被设置为 wrap_content,需要在监听器 ViewTreeObserver.OnGlobalLayoutListener() 中获取 View 的高度。下面这个函数组合了图片和文本:

private SpannableStringBuilder addImageToText(Context context, int drawableId, String text, int height) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    int width = height * drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
    drawable.setBounds(0, 0, width, height);

    SpannableStringBuilder ssb = new SpannableStringBuilder(" " + text);
    ssb.setSpan(new ImageSpan(drawable), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

    return ssb;
}

返回的参数可以直接喂给 TextView.setText(CharSequence text)完整代码参阅 gist

ClickableSpan:点击链接调出浏览器

需要两步:

  1. 覆写 ClickableSpan.onClick 方法;
  2. 为包含 ClickableSpan 的 TextView 设置 MovementMethod;
    private void setUrlSpanText(TextView textView, final String url) {
        SpannableStringBuilder ssb = new SpannableStringBuilder(CONTENT);
        ssb.setSpan(new ClickableSpan() {
            @Override
            public void onClick(View widget) {
                Toast.makeText(SpannableStringApiActivity.this, url, Toast.LENGTH_LONG).show();
                Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                startActivity(i);
            }
        }, START, END, 0);
        textView.setText(ssb);
	
        // setting the MovementMethod on the TextView that contains the span,
        // otherwise onClick will not be called.
        textView.setMovementMethod(LinkMovementMethod.getInstance());
    }

完整代码参阅 Github/SpannableTextActivity.java


知识共享许可协议
li2的博客WeiYi.Li 创作,采用 知识共享 署名-非商业性使用 4.0 国际 许可协议进行许可。
© 2011-2017. All rights reserved by WeiYi.Li. Powerd by Jekyll & LinAnYa's Theme