2017-07-09 10 views
1

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); 

    } 
} 

Antwort

1

Ihr Problem ist, dass Sie Instanzen der Spannen wiederverwenden. Per Dokumentation von setSpan (Hervorhebung von mir):

Bringen Sie das angegebene Markup-Objekt auf den Bereich Start ... Ende des Textes, oder das Objekt in diesem Bereich bewegen, wenn es bereits an anderer Stelle befestigt war.

Sie müssen also einfach jedes Mal neue Spans erstellen, wenn Sie Text zuordnen möchten.

Hoffe, dass hilft!

+0

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. –

+0

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

+0

Das ist ein bisschen außerhalb des Umfangs für mich. Wird dies [antworten] (https://stackoverflow.com/a/21972806/5045878) funktionieren? –

Verwandte Themen