Ich arbeite an einem EditText, der fett, kursiv und unterstrichen Zeichen wie in dieser question erwähnt nehmen kann.Mein benutzerdefinierter EditText funktioniert nicht richtig
Ich habe EditText erweitert und die onTextChanged() Methode überschrieben. Mein Code funktioniert gut für das erste Auftreten von fett, kursiv, unterstrichene Eingabe, aber nach meinem zweiten Vorkommen wird das erste Vorkommen in normalen Text geändert.
Here is a gif depecting the problem
Hier ist die 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);
}
});
}
}
Und hier ist die erweiterte EditText Klasse dh 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);
}
}
Das löste das Problem, aber ein vorheriges Problem trat wieder auf. Gestern stellte ich diese Frage https://StackOverflow.com/q/44984121/5045878 und die Lösung für das Problem war, die Spannen wiederzuverwenden. –
Na klar, die Dinge werden langsam, wenn Sie jeden einzelnen Bereich jedes Mal neu zuordnen, wenn sich der Text ändert. Was Ihre Logik tun muss, ist zu bestimmen, ob Sie sich in der Mitte eines Bereichs befinden, und dann den vorhandenen, der aktiv ist, erneut zu verwenden. Wenn Sie einen neuen Bereich erstellen, erstellen Sie einen neuen Bereich nur für diesen Anwendungsfall, und verwenden Sie ihn anschließend erneut, bis er fertig ist. Wenn Sie dann Zeichen löschen, können Sie die nicht mehr verwendeten Bereiche wiederverwenden. Dies ist kompliziert und übersteigt den Umfang der gestellten Frage. – dominicoder
Das ist ein bisschen außerhalb des Umfangs für mich. Wird dies [antworten] (https://stackoverflow.com/a/21972806/5045878) funktionieren? –