经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
解决SpannableString在Android组件间传递时显示失效的问题
来源:cnblogs  作者:帅气陈吃苹果  时间:2019/4/8 12:41:17  对本文有异议

问题:在A activity中传递一个SpannableString到B activity中,并最终传递到B activity中的TextView中,但是没有展示出Span效果。

解决:阅读TextView.setText()方法

  1. // If suggestions are not enabled, remove the suggestion spans from the text
  2. if (!isSuggestionsEnabled()) {
  3. text = removeSuggestionSpans(text);
  4. }
  5. ...
  6. if (type == BufferType.EDITABLE || getKeyListener() != null
  7. || needEditableForNotification) {
  8. //略
  9. } else if (precomputed != null) {
  10. //略
  11. } else if (type == BufferType.SPANNABLE || mMovement != null) {
  12. text = mSpannableFactory.newSpannable(text);
  13. } else if (!(text instanceof CharWrapper)) {
  14. text = TextUtils.stringOrSpannedString(text);
  15. }

看到会根据BufferType对传入的text重新赋值,于是回溯找到传入BufferType的地方:

  1. public void setText(CharSequence text, BufferType type) {
  2. setText(text, type, true, 0);
  3. if (mCharWrapper != null) {
  4. mCharWrapper.mChars = null;
  5. }
  6. }

公有方法,传入BufferType,查看BufferType:

  1. /**
  2. * Type of the text buffer that defines the characteristics of the text such as static,
  3. * styleable, or editable.
  4. */
  5. public enum BufferType {
  6. NORMAL, SPANNABLE, EDITABLE
  7. }

可以看到BufferType是枚举类型,有三种类型,SpannableString实现了Spannable接口,那么这里选择SPANNABLE,尝试后还是没有span效果,又注意到setText方法中mSpannableFactory.newSpannable会重新生成一个SpannableString:

  1. public SpannableString(CharSequence source) {
  2. this(source, false /* ignoreNoCopySpan */);
  3. }
  4. public SpannableString(CharSequence source, boolean ignoreNoCopySpan) {
  5. super(source, 0, source.length(), ignoreNoCopySpan);
  6. }

可以看到,默认将整个source作为一个span,这显然不是我们想要的。

重新阅读setText源码,发现:

  1. // If suggestions are not enabled, remove the suggestion spans from the text
  2. if (!isSuggestionsEnabled()) {
  3. text = removeSuggestionSpans(text);
  4. }

如果没有开启suggestions,传递进去的text将被移除自身已有的span,看下 isSuggestionsEnabled()方法:

  1. public boolean isSuggestionsEnabled() {
  2. if (mEditor == null) return false;
  3. if ((mEditor.mInputType & InputType.TYPE_MASK_CLASS) != InputType.TYPE_CLASS_TEXT) {
  4. return false;
  5. }
  6. if ((mEditor.mInputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) > 0) return false;
  7. final int variation = mEditor.mInputType & EditorInfo.TYPE_MASK_VARIATION;
  8. return (variation == EditorInfo.TYPE_TEXT_VARIATION_NORMAL
  9. || variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT
  10. || variation == EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE
  11. || variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE
  12. || variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
  13. }

可以看到该方法的返回值都与mEditor有关,再看下mEditor:

  1. /**
  2. * {@link EditText} specific data, created on demand when one of the Editor fields is used.
  3. * See {@link #createEditorIfNeeded()}.
  4. */
  5. private Editor mEditor;

mEditor是特定数据,在使用编辑器字段之一时按需创建,再看下注释中mEditor的创建方法:

  1. private void createEditorIfNeeded() {
  2. if (mEditor == null) {
  3. mEditor = new Editor(this);
  4. }
  5. }

啊哦,创建mEditor的唯一方法是私有方法,也就是说没法通过改变isSuggestionsEnabled()返回值来取消移除已有的span。

回过头看SpannableString源码,发现SpannableString没有实现任何序列化接口,而我是把SpannableString作为CharSequence通过Intent来传递的,它将作为普通的CharSequence实现类对象传递到TextView.setText()中,所以,解决方法有两种:

1)在setText()需要传递SpannableString的地方,重新创建一个SpannableString;

2)重写SpannableString,继承自SpannableString并实现序列化接口,将自定义的SpannableString作为对象通过Intent来传递;

总结:在Android组件间进行数据传递时,如果是传递对象,通常都会考虑到数据是否实现了序列化接口,但在这种情况下,试图将SpannableString作为CharSequence的实现类在组件之间进行传递,在接收端获取到的CharSequence将不再是传递之前的实现类对象,同时也容易忽略掉我们真正需要的是传递一个对象,而通过Intent传递对象是需要实现序列化接口的。

原文链接:http://www.cnblogs.com/sqchen/p/10660941.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号