SpannableString在键盘变化时会失效

给编辑框加SpannableString之后图片是正常显示的,但再点一下编辑框,键盘弹上来之后SpannableString就失效了变成正常的文本了,这是什么情况啊

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7638881
  • 你也可以参考下这篇文章:SpannableString文本和图片一起显示
  • 你还可以看下android参考手册中的 android SpannableStringBuilder 这是一个文本类,其内容和标记都可以被改变。
  • 除此之外, 这篇博客: Android SpannableString的使用中的 SpannableString基本用法 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

  • SpannableString用于为TextView组件的文本内容设置样式,相当于文本内容的CSS。常用于TextView与EditText。使用方式如下:

    //待显示文本
    String str = "零一二三四五六七八九十";
    //创建SpannableString对象
    SpannableString spannableStr = new SpannableString(str);
    //创建样式对象
    ForegroundColorSpan fcs = new ForegroundColorSpan(Color.RED);
    //绑定样式
    spannableStr.setSpan(fcs, 1, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    //显示
    mEditText1.setText(spannableStr);

    Android为了SpannableString设计了多种样式,常见的有文本颜色、字体样式(粗体,斜体)、删除线、下划线、链接效果等等。下面有对其详细介绍。
    这里主要说一下setSpan方法,setSpan(Object what, int start, int end, int flags)方法需要传递四个对象,what表示样式,start表示格式字符串起始下标,end表示格式字符串终了下标,flags用于控制字符长度变化时改变字符的显示样式。flags常用属性包括以下四种:

    • Spanned.SPAN_INCLUSIVE_EXCLUSIVE
      从start位置插入字符时应用样式,从end位置插入字符时不应用样式。
    • Spanned.SPAN_INCLUSIVE_INCLUSIVE
      从start位置以及end位置插入字符时都会应用样式。
    • Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
      从start位置以及end位置插入字符都不会应用样式。
    • Spanned.SPAN_EXCLUSIVE_INCLUSIVE
      从start位置插入字符时不会应用样式,从end位置插入字符时会应用样式。

    flags不太容易理解,建议写个demo使用EditText亲自体验一下:

    mEditText1 = (EditText) findViewById(R.id.editText1);
    mEditText2 = (EditText) findViewById(R.id.editText2);
    mEditText3 = (EditText) findViewById(R.id.editText3);
    mEditText4 = (EditText) findViewById(R.id.editText4);
    
    String str = "零一二三四五六七八九十";
    
    SpannableString ss1 = new SpannableString(str);
    SpannableString ss2 = new SpannableString(str);
    SpannableString ss3 = new SpannableString(str);
    SpannableString ss4 = new SpannableString(str);
    
    ForegroundColorSpan fcs = new ForegroundColorSpan(Color.RED);
    
    ss1.setSpan(fcs, 1, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    ss2.setSpan(fcs, 1, 5, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
    ss3.setSpan(fcs, 1, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    ss4.setSpan(fcs, 1, 5, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    
    mEditText1.setText(ss1);
    mEditText2.setText(ss2);
    mEditText3.setText(ss3);
    mEditText4.setText(ss4);
  • 以下回答由chatgpt基于相关博客总结生成:

    根据问题描述,当再次点击编辑框,键盘弹出后,SpannableString就会失效,文本会变成正常文本。这可能是因为键盘弹出后,编辑框重新绘制,而重新绘制会导致之前设置的SpannableString失效。可以尝试在编辑框重新绘制时重新应用SpannableString来解决这个问题。

    具体解决方法如下:

    1. 创建一个自定义的EditText,命名为CustomEditText。
    public class CustomEditText extends EditText {
    
        public CustomEditText(Context context) {
            super(context);
            init();
        }
    
        public CustomEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public CustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            // 添加EditText的文本改变监听器
            addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    // 在文本改变之前,暂停SpannableString的设置
                    clearSpans();
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    // 文本改变时,重新应用SpannableString
                    applySpannableString();
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    // 文本改变之后,重新恢复SpannableString的设置
                    applySpans();
                }
            });
        }
    
        // 重新应用SpannableString
        private void applySpannableString() {
            // 获取之前设置过的SpannableString
            SpannableString spannableString = getSpannableString();
    
            if (spannableString != null) {
                int start = getSelectionStart();
                int end = getSelectionEnd();
                spannableString.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                setText(spannableString);
                setSelection(start, end);
            }
        }
    
        // 清除之前设置过的所有Span
        private void clearSpans() {
            SpannableString spannableString = getSpannableString();
    
            if (spannableString != null) {
                ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);
                for (ForegroundColorSpan span : spans) {
                    spannableString.removeSpan(span);
                }
            }
        }
    
        // 将之前设置过的所有Span重新应用到EditText上
        private void applySpans() {
            SpannableString spannableString = getSpannableString();
    
            if (spannableString != null) {
                ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);
                for (ForegroundColorSpan span : spans) {
                    spannableString.setSpan(span, 0, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                }
            }
        }
    
        // 获取之前设置过的SpannableString
        private SpannableString getSpannableString() {
            CharSequence text = getText();
    
            if (text instanceof SpannableString) {
                return (SpannableString) text;
            }
    
            return null;
        }
    }
    
    1. 在布局文件中使用自定义的EditText,替换原有的EditText。
    <com.example.CustomEditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    

    通过重写EditText的相关方法,我们可以在每次文本改变时重新应用之前设置过的SpannableString,从而解决键盘弹出后失效的问题。注意,在应用SpannableString时需要保留之前的光标位置,以保证用户的编辑体验。

    希望这个解决方案对你有帮助。如果还有其他问题,请随时提问。

键盘弹出重新设置下SpannableString。 键盘弹出之后是否触发了EditText的焦点事件。可以短点调试下。