EditText 富文本学习七-实现微博热门话题@,#选择好友,整体删除,整体选中功能(思路,简单实例,提取于其他库)

1首先看效果(有点粗糙)

整体删除:
在这里插入图片描述
整体选择:
在这里插入图片描述
@#符号监听:
在这里插入图片描述

2 实现代码

整体删除功能,要删除一个热门话题需要整体进行删除:

 mEditText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
            //监听删除操作,找到最靠近删除的一个Span,然后整体选中
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    final int selectionStart = Selection.getSelectionStart(mEditText.getText());
                    final int selectionEnd = Selection.getSelectionEnd(mEditText.getText());

                    final ForegroundColorSpan spans[] = mEditText.getText().getSpans(selectionStart, selectionEnd, ForegroundColorSpan.class);
                    for (ForegroundColorSpan span : spans) {
                        if (span == null) {
                            continue;
                        }
                        if (mEditText.getText().getSpanEnd(span) == selectionStart) {
                            final int spanStart = mEditText.getText().getSpanStart(span);
                            final int spanEnd = mEditText.getText().getSpanEnd(span);
                            Selection.setSelection(mEditText.getText(), spanStart, spanEnd);
                            return selectionStart == selectionEnd;
                        }
                    }
                    return false;
                }
                return false;
            }
        });

整体选择,选择文本时需要整体选择,类似上面的删除:
mEditText.setEditableFactory(new NoCopySpanEditableFactory(new MySpanWatcher()));
利用setEditableFactory设置SpanWatcher来监听选择。

public class NoCopySpanEditableFactory extends Editable.Factory {

    private final NoCopySpan[] mSpans;

    public NoCopySpanEditableFactory(NoCopySpan... spans ) {
        this.mSpans = spans;
    }

    @Override
    public Editable newEditable( CharSequence source ) {
        final SpannableStringBuilder builder = SpannableStringBuilder.valueOf( source );
        if ( mSpans != null && mSpans.length > 0 ) {
            for ( NoCopySpan span : mSpans ) {
                if ( span == null ) {
                    continue;
                }
                builder.setSpan( span, 0, source.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE );
            }
        }
        return builder;
    }
}
public class MySpanWatcher implements SpanWatcher {
    @Override
    public void onSpanAdded(Spannable text, Object what, int start, int end) {

    }

    @Override
    public void onSpanRemoved(Spannable text, Object what, int start, int end) {

    }

    private int selectStart = 0;
    private int selectEnd = 0;

    @Override
    public void onSpanChanged( Spannable text, Object what, int ostart, int oend, int nstart, int nend ) {

        if ( what == Selection.SELECTION_END && selectEnd != nstart ) {
            selectEnd = nstart;
            ForegroundColorSpan spans[] = text.getSpans( nstart, nend, ForegroundColorSpan.class );
            if ( spans != null && spans.length > 0 ) {
                ForegroundColorSpan span = spans[0];
                if ( span != null ) {
                    final int spanStart = text.getSpanStart( span );
                    final int spanEnd = text.getSpanEnd( span );
                    int index = Math.abs( selectEnd - spanEnd ) > Math.abs( selectEnd - spanStart ) ? spanStart : spanEnd;
                    Selection.setSelection( text, Selection.getSelectionStart( text ), index );
                }
            }
        }

        if ( what == Selection.SELECTION_START && selectStart != nstart ) {
            selectStart = nstart;
            ForegroundColorSpan spans[] = text.getSpans( nstart, nend, ForegroundColorSpan.class );
            if ( spans != null && spans.length > 0 ) {
                ForegroundColorSpan span = spans[0];
                if ( span != null ) {
                    final int spanStart = text.getSpanStart( span );
                    final int spanEnd = text.getSpanEnd( span );
                    int index = Math.abs( selectStart - spanEnd ) > Math.abs( selectStart - spanStart ) ? spanStart : spanEnd;
                    Selection.setSelection( text, index, Selection.getSelectionEnd( text ) );
                }
            }
        }
    }
}

@#符号监听:

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

            }

            //参数解释原有的文本s中,从start开始的count个字符替换长度为before的旧文本,如果输入@,一般是从start开始替换before为0的1一个字符
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            //选中最后一个输入的字符,是@或者#打开新的页面
                if ( before == 0 && count > 0 ) {
                    int selectionStart = Selection.getSelectionStart(mEditText.getText()) == -1 ? 0 :  Selection.getSelectionStart(mEditText.getText());
                    int selectionEnd =  Selection.getSelectionEnd(mEditText.getText()) == -1 ? 0 :  Selection.getSelectionEnd(mEditText.getText());
                    //当前没有被选中的文本
                    if ( selectionStart != selectionEnd ) {
                        return;
                    }
                    if ( selectionStart == 0 ) {
                        return;
                    }
                    final CharSequence seq = s.subSequence( selectionStart - 1, selectionStart );
                    if ( TextUtils.isEmpty( seq ) ) {
                        return;
                    }

                    if (seq .toString().equals("#")){
                        Toast.makeText(DeleteSpanActivity.this,"输入了#,弹起界面",Toast.LENGTH_SHORT).show();
                    }

                    if (seq .toString().equals("@")){
                        Toast.makeText(DeleteSpanActivity.this,"输入了@,弹起界面",Toast.LENGTH_SHORT).show();
                    }

                } 
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

3 完整代码

Activity

public class DeleteSpanActivity extends AppCompatActivity {
    EditText mEditText;
    TextView mTextView;
    View mShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_delete_span);
        mEditText = findViewById(R.id.edit_text);
        mTextView = findViewById(R.id.text_view);
        mTextView.setMovementMethod(LinkMovementMethod.getInstance());
        mShow = findViewById(R.id.text_show);
        mShow.setOnClickListener(v -> {
            Intent intent = new Intent(this, VideoPlayerActivity.class);
            startActivity(intent);
        });

        mEditText.setEditableFactory(new NoCopySpanEditableFactory(new MySpanWatcher()));

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

            }

            //参数解释原有的文本s中,从start开始的count个字符替换长度为before的旧文本,如果输入@,一般是从start开始替换before为0的1一个字符
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if ( before == 0 && count > 0 ) {
                    int selectionStart = Selection.getSelectionStart(mEditText.getText()) == -1 ? 0 :  Selection.getSelectionStart(mEditText.getText());
                    int selectionEnd =  Selection.getSelectionEnd(mEditText.getText()) == -1 ? 0 :  Selection.getSelectionEnd(mEditText.getText());
                    if ( selectionStart != selectionEnd ) {
                        return;
                    }
                    if ( selectionStart == 0 ) {
                        return;
                    }
                    final CharSequence selectionPrevCharSeq = s.subSequence( selectionStart - 1, selectionStart );
                    if ( TextUtils.isEmpty( selectionPrevCharSeq ) ) {
                        return;
                    }

                    if (selectionPrevCharSeq.toString().equals("#")){
                        Toast.makeText(DeleteSpanActivity.this,"输入了#,弹起界面",Toast.LENGTH_SHORT).show();
                    }

                    if (selectionPrevCharSeq.toString().equals("@")){
                        Toast.makeText(DeleteSpanActivity.this,"输入了@,弹起界面",Toast.LENGTH_SHORT).show();
                    }

                } else if ( before > 0 && count == 0 ) {

                }
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
        mEditText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    final int selectionStart = Selection.getSelectionStart(mEditText.getText());
                    final int selectionEnd = Selection.getSelectionEnd(mEditText.getText());

                    final ForegroundColorSpan spans[] = mEditText.getText().getSpans(selectionStart, selectionEnd, ForegroundColorSpan.class);
                    for (ForegroundColorSpan span : spans) {
                        if (span == null) {
                            continue;
                        }
                        if (mEditText.getText().getSpanEnd(span) == selectionStart) {
                            final int spanStart = mEditText.getText().getSpanStart(span);
                            final int spanEnd = mEditText.getText().getSpanEnd(span);
                            Selection.setSelection(mEditText.getText(), spanStart, spanEnd);
                            return selectionStart == selectionEnd;
                        }
                    }
                    return false;
                }
                return false;
            }
        });

        mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mEditText != null && mEditText.getText() != null) {
                    String newText = "我是Span";
                    SpannableStringBuilder spannableString = new SpannableStringBuilder(mEditText.getText());
                    spannableString.append(newText);
                    ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.RED);
                    spannableString.setSpan(colorSpan, spannableString.length() - newText.length(), spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    mEditText.setText(spannableString);
                    mEditText.setSelection(spannableString.length());
                }
            }
        });
    }
}

XML文件:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DeleteSpanActivity">

    <EditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:gravity="start|top"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/edit_text"
        android:layout_marginRight="20dp"
        android:text="添加Span"/>

    <TextView
        android:id="@+id/text_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@+id/text_view"
        app:layout_constraintTop_toBottomOf="@+id/edit_text"
        android:visibility="gone"
        android:text="显示播放器"/>

</android.support.constraint.ConstraintLayout>

**NoCopySpanEditableFactory **

public class NoCopySpanEditableFactory extends Editable.Factory {

    private final NoCopySpan[] mSpans;

    public NoCopySpanEditableFactory(NoCopySpan... spans ) {
        this.mSpans = spans;
    }

    @Override
    public Editable newEditable( CharSequence source ) {
        final SpannableStringBuilder builder = SpannableStringBuilder.valueOf( source );
        if ( mSpans != null && mSpans.length > 0 ) {
            for ( NoCopySpan span : mSpans ) {
                if ( span == null ) {
                    continue;
                }
                builder.setSpan( span, 0, source.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE );
            }
        }
        return builder;
    }
}

**MySpanWatcher **

public class MySpanWatcher implements SpanWatcher {
    @Override
    public void onSpanAdded(Spannable text, Object what, int start, int end) {

    }

    @Override
    public void onSpanRemoved(Spannable text, Object what, int start, int end) {

    }

    private int selectStart = 0;
    private int selectEnd = 0;

    @Override
    public void onSpanChanged( Spannable text, Object what, int ostart, int oend, int nstart, int nend ) {

        if ( what == Selection.SELECTION_END && selectEnd != nstart ) {
            selectEnd = nstart;
            ForegroundColorSpan spans[] = text.getSpans( nstart, nend, ForegroundColorSpan.class );
            if ( spans != null && spans.length > 0 ) {
                ForegroundColorSpan span = spans[0];
                if ( span != null ) {
                    final int spanStart = text.getSpanStart( span );
                    final int spanEnd = text.getSpanEnd( span );
                    int index = Math.abs( selectEnd - spanEnd ) > Math.abs( selectEnd - spanStart ) ? spanStart : spanEnd;
                    Selection.setSelection( text, Selection.getSelectionStart( text ), index );
                }
            }
        }

        if ( what == Selection.SELECTION_START && selectStart != nstart ) {
            selectStart = nstart;
            ForegroundColorSpan spans[] = text.getSpans( nstart, nend, ForegroundColorSpan.class );
            if ( spans != null && spans.length > 0 ) {
                ForegroundColorSpan span = spans[0];
                if ( span != null ) {
                    final int spanStart = text.getSpanStart( span );
                    final int spanEnd = text.getSpanEnd( span );
                    int index = Math.abs( selectStart - spanEnd ) > Math.abs( selectStart - spanStart ) ? spanStart : spanEnd;
                    Selection.setSelection( text, index, Selection.getSelectionEnd( text ) );
                }
            }
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值