「=10=」SetSpan与Editxt

android setSpan to editText

很长一段时间我都对 setSpan 感到困惑,因为它看起来很简单但并不总是按预期工作

在我最后一次尝试中,我试图 setSpan 识别模式。 当用户开始输入“5 kilo toma”时,“5 kilo”将突出显示。

我使用下一个代码作为 TextWatcher 侦听器的一部分来执行此操作

@Override
    public void afterTextChanged(Editable s) {

        String quantity = mAutoCompleteAdapter.getQuantity();

        if (!quantity.isEmpty()) {
            int index = mAutoCompleteAdapter.getQuantityIndex();
            final StyleSpan styleSpan = new StyleSpan( Typeface.BOLD_ITALIC );
            s.setSpan( styleSpan, index, index + quantity.length(), Spanned.SPAN_MARK_MARK );
        }
    }

这工作正常(基本测试)

但是,如果我开始删除文本以读取“5 kil”,则当不再检测到模式时,setSpan 不会刷新为正常

所以我在想,也许 setSpan 保存在内存中或其他东西中,我每次都需要设置整个字符串跨度。所以我尝试了下一个代码:

@Override
    public void afterTextChanged(Editable s) {

        if (s.length() > 0) {

            String quantity = mAutoCompleteAdapter.getQuantity();
            int index = 0;

            if (!quantity.isEmpty()) {
                index = mAutoCompleteAdapter.getQuantityIndex();
                StyleSpan styleSpan = new StyleSpan( Typeface.BOLD_ITALIC );
                s.setSpan( styleSpan, index, index + quantity.length(), Spanned.SPAN_MARK_MARK );
            }

            StyleSpan styleSpanNormal = new StyleSpan( Typeface.NORMAL );
            s.setSpan( styleSpanNormal, index + quantity.length(), s.length(), Spanned.SPAN_MARK_MARK );
        }
    }

但仍然无法正常工作

我认为你应该尝试 textChangedListener 因为它的方法 onTextChanged 将帮助你在用户输入新文本时检查文本,删除文本视图中的一些文本

textview.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after{

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
               //place your code here
               //the code here will work when user is changing the text

            }

我想我现在更明白了。

如有错误请指正,不要着急降级

我很困惑地认为 EditText.getText() 正在返回 String,甚至当我看到 afterTextChanged(Editable s) 使用 Editable 时,我仍然认为它是一个相似的对象。

直到现在我注意到我可以使用 getText(),然后是 setSpan 而无需使用 setText,我才意识到我实际上是在获取实际对象并因此直接操作它。

意思是每一个 getText() 或使用 TextWatcher 监听器,旧的 setSpan 仍然存在,我需要清除它。

起初我以为 clearSpans() 可以解决问题,但它似乎也清除了其他所有内容。因此,我首先设置默认跨度,然后才设置正确的跨度

例如:

//Clear old span
s.setSpan( new BackgroundColorSpan( Color.TRANSPARENT),
                0,
                s.length(),
                Spanned.SPAN_MARK_MARK );

//set new span
s.setSpan( new BackgroundColorSpan( Color.RED),
                    indexStart,
                    indexStart + mQuantity.length(),
                    Spanned.SPAN_MARK_MARK );

此外,我注意到自动完成适配器和 TextWatcher 的顺序并不总是相同。使用日志时,我注意到大多数情况下 TextWatcher 在自动完成之前触发,但并非总是如此。要么那个,要么一个可以开火,另一个可以开火?!我不知道。

无论如何,由于适配器检查文本时顺序很重要,所以我使用 MutableLiveData<String> 来跟踪 mQuantity 值并相应地修改跨度

//In AutoComplete adapter
public MutableLiveData<String> getQuantity() {
    if (mQuantity == null) {
        mQuantity = new MutableLiveData<>();
    }
    return mQuantity;
}

//In handler constructor
mAutoCompleteAdapter.getQuantity().observe( (LifecycleOwner) activity, new 
Observer<String>() {
        @Override
        public void onChanged(String s) {
            mQuantity = s;
            refreshSpans();
        }
    } );

private void refreshSpans() {
    Editable s = mTextView.getText();
    clearEditTextSpan(s);

    if (!mQuantity.isEmpty()) {
        //Set span
        int indexStart = mAutoCompleteAdapter.getQuantityIndex();

        s.setSpan( new BackgroundColorSpan( Color.RED),
                indexStart,
                indexStart + mQuantity.length(),
                Spanned.SPAN_MARK_MARK );
    } 
}

private void clearEditTextSpan(Editable s) {
    s.setSpan( new BackgroundColorSpan( Color.TRANSPARENT),
            0,
            s.length(),
            Spanned.SPAN_MARK_MARK );
}

希望对大家有所帮助。