我的自定义EditText无法正常工作 [英] My Custom EditText not working correctly
问题描述
我正在研究一个EditText,它可以接受此问题中提到的粗体,斜体和下划线字符..
I am working on a EditText which can take Bold, Italics and Underline characters as mentioned in this question.
我扩展了EditText并覆盖了onTextChanged()方法. 对于任何粗体,斜体,带下划线的输入,我的代码都可以正常工作,但第二次出现后,第一次出现的情况将变为普通文本.
I have extended EditText and overrided the onTextChanged() method. My code works fine for the first occcurence of any bold, italics, underlined input but after my second occurence the first occurence gets changed to normal text.
这是MainActivity.java
package com.example.syed.andtexteditor;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
int helperCounterB = 0;
int helperCounterI = 0;
int helperCounterU = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button boldButton = (Button) findViewById(R.id.bold_button);
boldButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Button boldButton = (Button) findViewById(R.id.bold_button);
helperCounterB++;
if (helperCounterB % 2 != 0)
//The EditText is in Bold mode when the Bold button is pressed odd-th time
boldButton.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.black));
else
boldButton.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.grey));
TextArea t = (TextArea) findViewById(R.id.textInput);
t.applyTypeface(helperCounterI, helperCounterB, helperCounterU);
}
});
Button italicsButton = (Button) findViewById(R.id.italics_button);
italicsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Button italicsButton = (Button) findViewById(R.id.italics_button);
helperCounterI++;
if (helperCounterI % 2 != 0) //The EditText is in Italics mode when the Italics button is pressed odd-th time
italicsButton.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.black));
else
italicsButton.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.grey));
TextArea t = (TextArea) findViewById(R.id.textInput);
t.applyTypeface(helperCounterI, helperCounterB, helperCounterU);
}
});
Button underlineButton = (Button) findViewById(R.id.underline_button);
underlineButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Button underlineButton = (Button) findViewById(R.id.underline_button);
helperCounterU++;
if (helperCounterU % 2 != 0)//The EditText is in Underline mode when the Underline button is pressed odd-th time
underlineButton.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.black));
else
underlineButton.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.grey));
TextArea t = (TextArea) findViewById(R.id.textInput);
t.applyTypeface(helperCounterI, helperCounterB, helperCounterU);
}
});
}
}
这是扩展的EditText类,即TextArea.java
package com.example.syed.andtexteditor;
import android.content.Context;
import android.graphics.Typeface;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.CharacterStyle;
import android.text.style.StyleSpan;
import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
import android.util.Log;
/**
* Created by Syed on 29-05-2017.
*/
public class TextArea extends AppCompatEditText {
Context c;
public static final int TYPEFACE_NORMAL = 0;
public static final int TYPEFACE_BOLD = 1;
public static final int TYPEFACE_ITALICS = 2;
public static final int TYPEFACE_BOLD_ITALICS = 3;
public static final int TYPEFACE_UNDERLINE = 4;
public static final int TYPEFACE_BOLD_UNDERLINE = 5;
public static final int TYPEFACE_ITALICS_UNDERLINE = 6;
public static final int TYPEFACE_BOLD_ITALICS_UNDERLINE = 7;
private int currentTypeface;
private int lastCursorPosition;
private StyleSpan normalspan = new StyleSpan(Typeface.NORMAL);
private StyleSpan boldspan = new StyleSpan(Typeface.BOLD);
private StyleSpan italicspan = new StyleSpan(Typeface.ITALIC);
private StyleSpan boldItalicspan = new StyleSpan(Typeface.BOLD_ITALIC);
private UnderlineSpan underlinespan = new UnderlineSpan();
public TextArea(Context context) {
super(context);
c = context;
lastCursorPosition = this.getSelectionStart();
}
public TextArea(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void changeTypeface(int tfId) {
currentTypeface = tfId;
lastCursorPosition = this.getSelectionStart();
}
public void applyTypeface(int helperCounterI, int helperCounterB, int helperCounterU) {
int min = 0;
int max = this.getText().length();
if (this.isFocused()) {
final int selStart = this.getSelectionStart();
final int selEnd = this.getSelectionEnd();
min = Math.max(0, Math.min(selStart, selEnd));
max = Math.max(0, Math.max(selStart, selEnd));
}
Spannable s = this.getText();
Editable selectedText = new SpannableStringBuilder(s, min, max);
SpannableStringBuilder s1 = new SpannableStringBuilder(s, 0, min);
String selectedTextString = selectedText.toString();
SpannableStringBuilder selectedSpannedString = new SpannableStringBuilder(selectedTextString);
Log.d(VIEW_LOG_TAG, "Helper Counter I: " + helperCounterI + " Helper Counter B: " + helperCounterB);
if (helperCounterI % 2 != 0 && helperCounterB % 2 != 0 && helperCounterU % 2 == 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TextArea.TYPEFACE_BOLD_ITALICS);
}
//ignore this part as there are no issues with this
else {
StyleSpan styleSpan = new StyleSpan(Typeface.BOLD_ITALIC);
selectedSpannedString.setSpan(styleSpan, min, max, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
} else if (helperCounterI % 2 != 0 && helperCounterB % 2 == 0 && helperCounterU % 2 == 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TextArea.TYPEFACE_ITALICS);
}
//ignore this part as there are no issues with this
else {
StyleSpan styleSpan = new StyleSpan(Typeface.ITALIC);
selectedSpannedString.setSpan(styleSpan, min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
} else if (helperCounterI % 2 == 0 && helperCounterB % 2 != 0 && helperCounterU % 2 == 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TextArea.TYPEFACE_BOLD);
}
//ignore this part as there are no issues with this
else {
StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
selectedSpannedString.setSpan(styleSpan, min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
} else if (helperCounterB % 2 == 0 && helperCounterI % 2 == 0 && helperCounterU % 2 == 0) {
this.changeTypeface(TextArea.TYPEFACE_NORMAL);
} else if (helperCounterU % 2 != 0 && helperCounterI % 2 == 0 && helperCounterB % 2 == 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TYPEFACE_UNDERLINE);
}
//ignore this part as there are no issues with this
else {
selectedSpannedString.setSpan(new UnderlineSpan(), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
} else if (helperCounterU % 2 != 0 && helperCounterI % 2 == 0 && helperCounterB % 2 != 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TYPEFACE_BOLD_UNDERLINE);
}
//ignore this part as there are no issues with this
else {
selectedSpannedString.setSpan(new StyleSpan(Typeface.BOLD), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
selectedSpannedString.setSpan(new UnderlineSpan(), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
} else if (helperCounterU % 2 != 0 && helperCounterI % 2 != 0 && helperCounterB % 2 == 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TYPEFACE_ITALICS_UNDERLINE);
} else
//ignore this part as there are no issues with this
{
selectedSpannedString.setSpan(new StyleSpan(Typeface.ITALIC), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
selectedSpannedString.setSpan(new UnderlineSpan(), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
} else if (helperCounterU % 2 != 0 && helperCounterI % 2 != 0 && helperCounterB % 2 != 0) {
if (this.getSelectionEnd() == this.getSelectionStart()) {
this.changeTypeface(TYPEFACE_BOLD_ITALICS_UNDERLINE);
}
//ignore this part as there are no issues with this
else {
selectedSpannedString.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
selectedSpannedString.setSpan(new UnderlineSpan(), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder s3 = new SpannableStringBuilder(s, max, s.length());
CharSequence finalSpannable = TextUtils.concat(s1, selectedSpannedString, s3);
this.setText(finalSpannable);
}
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
Log.d(VIEW_LOG_TAG, "Start: " + start + " Length before: " + lengthBefore + " Length After: " + lengthAfter + " TextLength: " + text.length());
CharacterStyle ss = null;
UnderlineSpan ss1 = null;
int endLength = text.toString().length();
switch (currentTypeface) {
case TYPEFACE_NORMAL:
ss = normalspan;
break;
case TYPEFACE_BOLD:
ss = boldspan;
break;
case TYPEFACE_ITALICS:
ss = italicspan;
break;
case TYPEFACE_BOLD_ITALICS:
ss = boldItalicspan;
break;
case TYPEFACE_UNDERLINE:
ss = underlinespan;
break;
case TYPEFACE_BOLD_UNDERLINE:
ss = boldspan;
ss1 = underlinespan;
break;
case TYPEFACE_ITALICS_UNDERLINE:
ss = italicspan;
ss1 = underlinespan;
break;
case TYPEFACE_BOLD_ITALICS_UNDERLINE:
ss = boldItalicspan;
ss1 = underlinespan;
break;
}
if (lastCursorPosition > endLength)
return;
Log.d(TextArea.class.getSimpleName(), new Integer(lastCursorPosition).toString() + new Integer(endLength).toString());
this.getText().setSpan(ss, lastCursorPosition, endLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
this.getText().setSpan(ss1, lastCursorPosition, endLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
推荐答案
Your problem is that you are re-using instances of the spans. Per the documentation of setSpan (emphasis mine):
将指定的标记对象附加到文本的开始范围...结尾处,或将对象移动到该范围,如果该对象已经附加在其他地方.
因此,每次您要为文本添加属性时,只需创建新的跨度即可.
So you simply need to create new Spans each time you want to attribute text.
希望有帮助!
这篇关于我的自定义EditText无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!