全国咨询热线:400-618-4000

Android培训之SpannableString的使用

更新时间:2019年03月21日18时00分 来源:Android培训学院

社交软件里的SpannableString的使用
实现类似微博的信息流展示
 
简介:社交软件里常见的emoji表情、@联系人等功能,可以在一个TextView里处理图片显示和文字点击等复杂的行为,通过此文档可以掌握该功能的实现方法。
 

1.基本知识

  1. SpannableString(复合字符串)类
该类的对象可被设置为TextView的正文,在显示原有文本的基础上,增加多种富文本特性。

  1. CharacterStyle(字符格式)的子类
在上面的setSpan方法可以看到需要一个object作为参数,该参数即为CharacterStyle的子类,有文本的前景颜色、点击、背景色、图片、下划线等格式可供使用。

2.可点击文本,如 #话题#、@联系人 的处理

  1.  先上代码
下面的代码使得字符串里的“只是”两个字符可被点击,点击时会弹出Toast提示。
 
 

 
下面分析代码里的几个参数

  1. str是用于显示的原始字符串
  2. 参数1,ClickableSpan对象
声明被修饰的字符串可以被点击。被点击时会回调onClick方法,要跳转界面还是要弹个Toast,根据业务需求变化。
  1. 参数2,start
该值表示要设置为clickspan的字符串起始位置,最小值为0.
  1. 参数3,end
该值表示要设置为clickspan的字符串终止位置,最大值为文本的length.
  1. 参数4,flags
该值用于说明,当被选中文字前后新增内容,新的字符是否受span影响。从使用来看,只在使用EditText的时候才会产生影响。信息流展示只要使用SPAN_EXCLUSIVE_EXCLUSIVE 即可。

  1. 参数5,MovementMethod对象
用于分析TextView使用的所有span,在TextView发生touch事件的时候会先交由movementMethod对象判断是否有CLickableSpan需要被处理。此参数必须设置,否则ClickableSpan的onClick方法不会被回调。
  1. 匹配#话题#或@联系人,并提供点击响应。
    1. 使用正则表达式确定start和end位置
从之前的代码可以看到,设置文字点击监听的代码是固定不变的,比较费脑的是怎么确定start和end的位置。#话题#和@联系人都是固定格式的字符串,查找固定格式的字符串应使用正则表达式来处理。上代码:
 
 

  1. 参数1,,正则表达式的查询规则
本文不做讲解,有需要请自行搜索“正则表达式”。
  1. 参数2,参数3,Pattern和Matcher
都是JDK里用于处理正则表达式的类,使用方法是固定的,可以参见代码注释。
  1. TopicClickableSpan
继承自ClickableSpan,由于ClickableSpan的onClick方法参数为View,无法区分出被点击的span,需要在构造方法里传递话题字符串以供区分不同的话题。

  1. @联系人的点击处理
更换正则表达式和自定义的ClickableSpan即可。

3.emoji表情的显示处理

  1. ImageSpan
可以将文字替换为图片显示,接收的图片可以是资源id也可以是Bitmap。
  1. Emoji表情
从服务器传过来的只是字符串,但是应该具备类似[/吓死]或者/xs这样的特殊格式,客户端通过正则表达式确定表情字符串的start和end位置,将文字转换为图片并显示到文本框。
 
 
 

  1. EmojiList类
根据匹配到的表情名称查找出来的对应图片id。用于封装所有的表情资源

4.将超链接转换为图片,并提供点击处理

通过正则表达式匹配到URL的start和end位置,并且同时设置ImageSpan和ClickableSpan到该段字符上,使得该段字符串同时具备两种特性
 
 
 


5.ClickSpan和ListView的item点击事件冲突解决


5.1存在的问题
当包含ClickableSpan的TextView作为ListView的item存在时,由于点击事件的处理冲突,会导致列表的点击事件无法响应。目前网络上的解决方案只能:“ClickableSpan响应 + item单击/长按”响应,本文可以则可以“ClickableSpan 响应+ item单击 + item长按 ”响应,并且不存在滑动时会长按响应的问题。
5.2处理方法分析
5.21处理焦点方法
TextView.setMovementMethod()方法会导致TextView的点击判断被修改,使得onTouchEvent方法始终返回为true,导致ListView无法获取touch事件,所以需要在setMovementMethod后将焦点等标志位设为false
5.22自定义MovementMethodLinkMovementMethod的onTouchEvent方法里最终会调用到Touch.onTouchEvent,该方法将down事件返回为true(见下图),使得TextView始终拦截Touch事件,导致ListView的item点击无法响应。所以需要自定义LinkMovementMethod
来修改down事件的返回值,同时在TextView的onTouchEvent里根据自定义的标志位来决定是否拦截touch事件。

  1. 自定义TextView
  1. 自定义LinkMovementMethod
  1. 使用方法
使用自定义的MyTextView,Textview.setMovementMethod()改为使用TextView. setLocalLinkMovementMethod(LocalLinkMovementMethod.getInstance());
当前的解决方案保证了只在有ClickableSpan被点击时TextView才拦截touch事件,也就使得ListView的点击事件可以正常响应了。
更多详情请查看帖子:
http://bbs.itheima.com/thread-276002-1-1.html
http://bbs.itheima.com/thread-276003-1-1.html
 

 本文版权归传智播客Android培训学院所有,欢迎转载,转载请注明作者出处。谢谢!
作者:传智播客Android培训学院
首发:http://www.itcast.cn/Android