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 ) );
}
}
}
}
}
网友评论