在Android中屏蔽格式为(XXX)XXX-XXXX ext.XXXXXX的EditText吗?

时间:2018-12-12 11:15:19

标签: android android-edittext

如何在Android中以以下格式屏蔽EditText

(XXX) XXX-XXXX ext.XXXXXX i.e (654) 321-5846 ext.654321

在“自定义编辑文本”类下使用

package com.test.PhoneNumberFormatter;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.os.Bundle;
    import android.os.Parcelable;
    import android.support.v7.widget.AppCompatEditText;
    import android.text.Editable;
    import android.text.SpannableStringBuilder;
    import android.text.TextWatcher;
    import android.text.style.ForegroundColorSpan;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.View;
    import android.widget.TextView;
    import com.test.R;
    import static android.content.ContentValues.TAG;
    public class MaskedEditText extends AppCompatEditText implements TextWatcher {
    public static final String SPACE = " ";
    private String mask;
    private char charRepresentation;
    private boolean keepHint;
    private int[] rawToMask;
    private RawText rawText;
    private boolean editingBefore;
    private boolean editingOnChanged;
    private boolean editingAfter;
    private int[] maskToRaw;
    private int selection;
    private boolean initialized;
    private boolean ignore;
    protected int maxRawLength;
    private int lastValidMaskPosition;
    private boolean selectionChanged;
    private OnFocusChangeListener focusChangeListener;
    private String allowedChars;
    private String deniedChars;


    public MaskedEditText(Context context) {
        super(context);
        init();
    }

    public MaskedEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.MaskedEditText);
        mask = attributes.getString(R.styleable.MaskedEditText_mask);

        allowedChars = attributes.getString(R.styleable.MaskedEditText_allowed_chars);
        deniedChars = attributes.getString(R.styleable.MaskedEditText_denied_chars);

        String representation = attributes.getString(R.styleable.MaskedEditText_char_representation);

        if (representation == null) {
            charRepresentation = '#';
        } else {
            charRepresentation = representation.charAt(0);
        }

        keepHint = attributes.getBoolean(R.styleable.MaskedEditText_keep_hint, false);

        cleanUp();

        // Ignoring enter key presses
        setOnEditorActionListener(new OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                switch (actionId) {
//              case EditorInfo.IME_ACTION_NEXT:
                    // fixing actionNext
//                  return false;
                    default:
                        return true;
                }
            }
        });
        attributes.recycle();
    }

    @Override
    public Parcelable onSaveInstanceState() {
        final Parcelable superParcellable = super.onSaveInstanceState();
        final Bundle state = new Bundle();
        state.putParcelable("super", superParcellable);
        state.putString("text", getRawText());
        state.putBoolean("keepHint", isKeepHint());
        return state;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        Bundle bundle = (Bundle) state;
        keepHint = bundle.getBoolean("keepHint", false);
        super.onRestoreInstanceState(((Bundle) state).getParcelable("super"));
        final String text = bundle.getString("text");

        setText(text);
        Log.d(TAG, "onRestoreInstanceState: " + text);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
//      if (text == null || text.equals("")) return;
        super.setText(text, type);
    }

    /**
     * @param listener - its onFocusChange() method will be called before performing MaskedEditText operations,
     *                 related to this event.
     */
    @Override
    public void setOnFocusChangeListener(OnFocusChangeListener listener) {
        focusChangeListener = listener;
    }

    private void cleanUp() {
        initialized = false;

        generatePositionArrays();

        rawText = new RawText();
        selection = rawToMask[0];

        editingBefore = true;
        editingOnChanged = true;
        editingAfter = true;
        if (hasHint() && rawText.length() == 0) {
            this.setText(makeMaskedTextWithHint());
        } else {
            this.setText(makeMaskedText());
        }
        editingBefore = false;
        editingOnChanged = false;
        editingAfter = false;

        maxRawLength = maskToRaw[previousValidPosition(mask.length() - 1)] + 1;
        lastValidMaskPosition = findLastValidMaskPosition();
        initialized = true;

        super.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (focusChangeListener != null) {
                    focusChangeListener.onFocusChange(v, hasFocus);
                }

                if (hasFocus()) {
                    selectionChanged = false;
                    MaskedEditText.this.setSelection(lastValidPosition());
                }
            }
        });
    }

    private int findLastValidMaskPosition() {
        for (int i = maskToRaw.length - 1; i >= 0; i--) {
            if (maskToRaw[i] != -1) return i;
        }
        throw new RuntimeException("Mask must contain at least one representation char");
    }

    private boolean hasHint() {
        return getHint() != null;
    }

    public MaskedEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public void setMask(String mask) {
        this.mask = mask;
        cleanUp();
    }

    public String getMask() {
        return this.mask;
    }

    public String getRawText() {
        return this.rawText.getText();
    }

    public void setCharRepresentation(char charRepresentation) {
        this.charRepresentation = charRepresentation;
        cleanUp();
    }

    public char getCharRepresentation() {
        return this.charRepresentation;
    }

    /**
     * Generates positions for values characters. For instance:
     * Input data: mask = "+7(###)###-##-##
     * After method execution:
     * rawToMask = [3, 4, 5, 6, 8, 9, 11, 12, 14, 15]
     * maskToRaw = [-1, -1, -1, 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, -1, 8, 9]
     * charsInMask = "+7()- " (and space, yes)
     */
    private void generatePositionArrays() {
        int[] aux = new int[mask.length()];
        maskToRaw = new int[mask.length()];
        String charsInMaskAux = "";

        int charIndex = 0;
        for (int i = 0; i < mask.length(); i++) {
            char currentChar = mask.charAt(i);
            if (currentChar == charRepresentation) {
                aux[charIndex] = i;
                maskToRaw[i] = charIndex++;
            } else {
                String charAsString = Character.toString(currentChar);
                if (!charsInMaskAux.contains(charAsString)) {
                    charsInMaskAux = charsInMaskAux.concat(charAsString);
                }
                maskToRaw[i] = -1;
            }
        }
        if (charsInMaskAux.indexOf(' ') < 0) {
            charsInMaskAux = charsInMaskAux + SPACE;
        }

        char[] charsInMask = charsInMaskAux.toCharArray();

        rawToMask = new int[charIndex];
        for (int i = 0; i < charIndex; i++) {
            rawToMask[i] = aux[i];
        }
    }

    private void init() {
        addTextChangedListener(this);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
                                  int after) {
        if (!editingBefore) {
            editingBefore = true;
            if (start > lastValidMaskPosition) {
                ignore = true;
            }
            int rangeStart = start;
            if (after == 0) {
                rangeStart = erasingStart(start);
            }
            Range range = calculateRange(rangeStart, start + count);
            if (range.getStart() != -1) {
                rawText.subtractFromString(range);
            }
            if (count > 0) {
                selection = previousValidPosition(start);
            }
        }
    }

    private int erasingStart(int start) {
        while (start > 0 && maskToRaw[start] == -1) {
            start--;
        }
        return start;
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (!editingOnChanged && editingBefore) {
            editingOnChanged = true;
            if (ignore) {
                return;
            }
            if (count > 0) {
                int startingPosition = maskToRaw[nextValidPosition(start)];
                String addedString = s.subSequence(start, start + count).toString();
                count = rawText.addToString(clear(addedString), startingPosition, maxRawLength);
                if (initialized) {
                    int currentPosition;
                    if (startingPosition + count < rawToMask.length)
                        currentPosition = rawToMask[startingPosition + count];
                    else
                        currentPosition = lastValidMaskPosition + 1;
                    selection = nextValidPosition(currentPosition);
                }
            }
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
        if (!editingAfter && editingBefore && editingOnChanged) {
            editingAfter = true;
            if (hasHint() && (keepHint || rawText.length() == 0)) {
                setText(makeMaskedTextWithHint());
            } else {
                setText(makeMaskedText());
            }

            selectionChanged = false;
            setSelection(selection);

            editingBefore = false;
            editingOnChanged = false;
            editingAfter = false;
            ignore = false;
        }
    }

    public boolean isKeepHint() {
        return keepHint;
    }

    public void setKeepHint(boolean keepHint) {
        this.keepHint = keepHint;
        setText(getRawText());
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        // On Android 4+ this method is being called more than 1 time if there is a hint in the EditText, what moves the cursor to left
        // Using the boolean var selectionChanged to limit to one execution

        if (initialized) {
            if (!selectionChanged) {
                selStart = fixSelection(selStart);
                selEnd = fixSelection(selEnd);

                // exactly in this order. If getText.length() == 0 then selStart will be -1
                if (selStart > getText().length()) selStart = getText().length();
                if (selStart < 0) selStart = 0;

                // exactly in this order. If getText.length() == 0 then selEnd will be -1
                if (selEnd > getText().length()) selEnd = getText().length();
                if (selEnd < 0) selEnd = 0;

                setSelection(selStart, selEnd);
                selectionChanged = true;
            } else {
                //check to see if the current selection is outside the already entered text
                if (selStart > rawText.length() - 1) {
                    final int start = fixSelection(selStart);
                    final int end = fixSelection(selEnd);
                    if (start >= 0 && end < getText().length()) {
                        setSelection(start, end);
                    }
                }
            }
        }
        super.onSelectionChanged(selStart, selEnd);
    }

    private int fixSelection(int selection) {
        if (selection > lastValidPosition()) {
            return lastValidPosition();
        } else {
            return nextValidPosition(selection);
        }
    }

    private int nextValidPosition(int currentPosition) {
        while (currentPosition < lastValidMaskPosition && maskToRaw[currentPosition] == -1) {
            currentPosition++;
        }
        if (currentPosition > lastValidMaskPosition) return lastValidMaskPosition + 1;
        return currentPosition;
    }

    private int previousValidPosition(int currentPosition) {
        while (currentPosition >= 0 && maskToRaw[currentPosition] == -1) {
            currentPosition--;
            if (currentPosition < 0) {
                return nextValidPosition(0);
            }
        }
        return currentPosition;
    }

    private int lastValidPosition() {
        if (rawText.length() == maxRawLength) {
            return rawToMask[rawText.length() - 1] + 1;
        }
        return nextValidPosition(rawToMask[rawText.length()]);
    }


    private String makeMaskedText() {
        int maskedTextLength;
        if (rawText.length() < rawToMask.length) {
            maskedTextLength = rawToMask[rawText.length()];
        } else {
            maskedTextLength = mask.length();
        }
        char[] maskedText = new char[maskedTextLength]; //mask.replace(charRepresentation, ' ').toCharArray();
        for (int i = 0; i < maskedText.length; i++) {
            int rawIndex = maskToRaw[i];
            if (rawIndex == -1) {
                maskedText[i] = mask.charAt(i);
            } else {
                maskedText[i] = rawText.charAt(rawIndex);
            }
        }
        return new String(maskedText);
    }

    private CharSequence makeMaskedTextWithHint() {
        SpannableStringBuilder ssb = new SpannableStringBuilder();
        int mtrv;
        int maskFirstChunkEnd = rawToMask[0];
        for (int i = 0; i < mask.length(); i++) {
            mtrv = maskToRaw[i];
            if (mtrv != -1) {
                if (mtrv < rawText.length()) {
                    ssb.append(rawText.charAt(mtrv));
                } else {
                    ssb.append(getHint().charAt(maskToRaw[i]));
                }
            } else {
                ssb.append(mask.charAt(i));
            }
            if ((keepHint && rawText.length() < rawToMask.length && i >= rawToMask[rawText.length()])
                    || (!keepHint && i >= maskFirstChunkEnd)) {
                ssb.setSpan(new ForegroundColorSpan(getCurrentHintTextColor()), i, i + 1, 0);
            }
        }
        return ssb;
    }

    private Range calculateRange(int start, int end) {
        Range range = new Range();
        for (int i = start; i <= end && i < mask.length(); i++) {
            if (maskToRaw[i] != -1) {
                if (range.getStart() == -1) {
                    range.setStart(maskToRaw[i]);
                }
                range.setEnd(maskToRaw[i]);
            }
        }
        if (end == mask.length()) {
            range.setEnd(rawText.length());
        }
        if (range.getStart() == range.getEnd() && start < end) {
            int newStart = previousValidPosition(range.getStart() - 1);
            if (newStart < range.getStart()) {
                range.setStart(newStart);
            }
        }
        return range;
    }

    private String clear(String string) {
        if (deniedChars != null) {
            for (char c : deniedChars.toCharArray()) {
                string = string.replace(Character.toString(c), "");
            }
        }

        if (allowedChars != null) {
            StringBuilder builder = new StringBuilder(string.length());

            for (char c : string.toCharArray()) {
                if (allowedChars.contains(String.valueOf(c))) {
                    builder.append(c);
                }
            }

            string = builder.toString();
        }

        return string;
    }
    }

在activity_main.xml中

<com.test.PhoneNumberFormatter.MaskedEditText
    android:id="@+id/phone_input"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:hint="@string/phone_number"
    android:imeOptions="actionNext"
    android:inputType="textPhonetic"
    android:paddingBottom="@dimen/_3sdp"
    android:paddingTop="@dimen/_8sdp"
    android:textColorHint="@color/grey_color"
    android:textSize="@dimen/_12sdp"
    mask:allowed_chars="1234567890ext."
    mask:keep_hint="false"
    mask:mask="(###)###-#### ext.######" />

谢谢。

3 个答案:

答案 0 :(得分:1)

对于“编辑文本”格式,以下内容可能对您有所帮助。

 **Step 1** : Add following line in your build.gradle file

  implementation 'com.github.pinball83:masked-edittext:1.0.4'

 **Step 2 :**  by xml :

 <com.github.pinball83.maskededittext.MaskedEditText
            android:id="@+id/masked_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="number"
            app:mask="8 (***) *** **-**"
            app:notMaskedSymbol="*"
            app:maskIcon="@drawable/abc_ic_clear_mtrl_alpha"
            app:maskIconColor="@color/colorPrimary"
            />

或通过Java文件:

 MaskedEditText maskedEditText = new MaskedEditText.Builder(context)
        .mask("8 (***) *** **-**")
        .notMaskedSymbol("*")
        .icon(R.drawable.ic_account_circle)
        .iconCallback(unmaskedText -> { //Icon click callback handler })
        .build();



 MaskedEditText editText = new MaskedEditText.Builder(context)
        .mask("8 (***) *** **-**")
        .notMaskedSymbol("*")
        .build();; //set mask to "8 (***) *** **-**" and not masked symbol to "*"

文本设置和格式

    MaskedEditText editText = new MaskedEditText..Builder(context)
        .mask("8 (***) *** **-**")
        .notMaskedSymbol("*")
        .format("[1][2][3] [4][5][6]-[7][8]-[10][9]")//set format of returned data input into MaskedEditText
        .build();

editText.setMaskedText(“ 5551235567”);

有关更多详细信息,请使用以下网址:

https://github.com/pinball83/Masked-Edittext

享受:)

答案 1 :(得分:0)

第1步:创建editText

<EditText
    android:id="@+id/masked_edit_text"
    android:layout_width="yourSize"
    android:layout_height="yourSize"
    android:inputType="textPassword"/>

第二步:

 public class CustomTransformation  extends PasswordTransformationMethod {
  @Override
  public CharSequence getTransformation(CharSequence source, View view) {
    return new TransformedSequence(source);
}

private class TransformedSequence implements CharSequence {

    private CharSequence sequence;

    public TransformedSequence(CharSequence source) {
        sequence = source; // Store char sequence
    }
    public char charAt(int index) {
        return 'X'; //  Replace with what you want.
    }
    public int length() {
        return sequence.length(); // return the length
    }
    public CharSequence subSequence(int start, int end) {
        return sequence.subSequence(start, end); //return  sequence
    }
}

第3步:应用转换

EditText edittext = findViewById(R.id.masked_edit_text);
edittext.setTransformationMethod(new CustomTransformation());

答案 2 :(得分:0)

https://github.com/mukeshsolanki/country-picker-android 试试这个图书馆。 这会自动用您选择的国家/地区号屏蔽您的编辑文本。