我的自定义EditText无法正常工作

时间:2017-07-09 15:51:30

标签: java android android-edittext

我正在使用EditText,它可以采用此question中提到的粗体,斜体和下划线字符。

我扩展了EditText并覆盖了onTextChanged()方法。 我的代码适用于任何粗体,斜体,下划线输入的第一次出现,但在我第二次出现后,第一次出现的内容变为普通文本。

Here is a gif depecting the problem

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

    }
}

1 个答案:

答案 0 :(得分:1)

您的问题是您正在重新使用跨度的实例。根据{{​​3}}(强调我的)的文档:

  

将指定的标记对象附加到文本的范围开始...结尾,或将对象移动到该范围(如果已经附加在其他地方)。

因此,每次要归档文本时,只需创建新的Spans。

希望有所帮助!