Phone number formatting an EditText in Android

前端 未结 14 915
情深已故
情深已故 2020-12-02 12:03

I am making a simple Address Book app (targeting 4.2) that takes name, address, city, state, zip and phone.

I want to format the phone number input as a phone number

相关标签:
14条回答
  • 2020-12-02 12:31

    Maybe below sample project helps you;

    https://github.com/reinaldoarrosi/MaskedEditText

    That project contains a view class call MaskedEditText. As first, you should add it in your project.

    Then you add below xml part in res/values/attrs.xml file of project;

    <resources>
        <declare-styleable name="MaskedEditText">
            <attr name="mask" format="string" />
            <attr name="placeholder" format="string" />
        </declare-styleable>
    </resources>
    

    Then you will be ready to use MaskedEditText view.

    As last, you should add MaskedEditText in your xml file what you want like below;

    <packagename.currentfolder.MaskedEditText
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/maskedEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:text="5"
        app:mask="(999) 999-9999"
        app:placeholder="_" >
    

    Of course that, you can use it programmatically.

    After those steps, adding MaskedEditText will appear like below;

    As programmatically, if you want to take it's text value as unmasked, you may use below row;

    maskedEditText.getText(true);
    

    To take masked value, you may send false value instead of true value in the getText method.

    0 讨论(0)
  • 2020-12-02 12:31
    //(123) 456 7890  formate set
    
    private int textlength = 0;
    
    public class MyPhoneTextWatcher implements TextWatcher {
    
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }
        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    
            String text = etMobile.getText().toString();
            textlength = etMobile.getText().length();
    
            if (text.endsWith(" "))
                return;
    
            if (textlength == 1) {
                if (!text.contains("(")) {
                    etMobile.setText(new StringBuilder(text).insert(text.length() - 1, "(").toString());
                    etMobile.setSelection(etMobile.getText().length());
                }
    
            } else if (textlength == 5) {
    
                if (!text.contains(")")) {
                    etMobile.setText(new StringBuilder(text).insert(text.length() - 1, ")").toString());
                    etMobile.setSelection(etMobile.getText().length());
                }
    
            } else if (textlength == 6 || textlength == 10) {
                etMobile.setText(new StringBuilder(text).insert(text.length() - 1, " ").toString());
                etMobile.setSelection(etMobile.getText().length());
            }
    
        }
        @Override
        public void afterTextChanged(Editable editable) {
        }
    }
    
    0 讨论(0)
  • 2020-12-02 12:32

    Simply use the PhoneNumberFormattingTextWatcher, just call:

    editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
    

    Addition
    To be clear, PhoneNumberFormattingTextWatcher's backbone is the PhoneNumberUtils class. The difference is the TextWatcher maintains the EditText while you must call PhoneNumberUtils.formatNumber() every time you change its contents.

    0 讨论(0)
  • 2020-12-02 12:32

    You can use spawns to format phone numbers in Android. This solution is better than the others because it does not change input text. Formatting remains purely visual.

    implementation 'com.googlecode.libphonenumber:libphonenumber:7.0.4'
    

    Formatter class:

    open class PhoneNumberFormatter : TransformationMethod {
    private val mFormatter: AsYouTypeFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(Locale.getDefault().country)
    
    override fun getTransformation(source: CharSequence, view: View): CharSequence {
        val formatted = format(source)
        if (source is Spannable) {
            setSpans(source, formatted)
            return source
        }
        return formatted
    }
    override fun onFocusChanged(view: View?, sourceText: CharSequence?, focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) = Unit
    
    private fun setSpans(spannable: Spannable, formatted: CharSequence): CharSequence {
    
        spannable.clearSpawns()
    
        var charterIndex = 0
        var formattedIndex = 0
        var spawn = ""
        val spawns: List<String> = spannable
            .map {
                spawn = ""
                charterIndex = formatted.indexOf(it, formattedIndex)
                if (charterIndex != -1){
                    spawn = formatted.substring(formattedIndex, charterIndex-1)
                    formattedIndex = charterIndex+1
                }
                spawn
            }
    
        spawns.forEachIndexed { index, sequence ->
            spannable.setSpan(CharterSpan(sequence), index, index + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
    
        return formatted
    }
    
    private fun Spannable.clearSpawns() =
        this
            .getSpans(0, this.length, CharterSpan::class.java)
            .forEach { this.removeSpan(it) }
    
    private fun format(spannable: CharSequence): String {
        mFormatter.clear()
        var formated = ""
        for (i in 0 until spannable.length) {
            formated = mFormatter.inputDigit(spannable[i])
        }
        return formated
    }
    
    private inner class CharterSpan(private val charters: String) : ReplacementSpan() {
    
        var space = 0
    
        override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
            space = Math.round(paint.measureText(charters, 0, charters.length))
            return Math.round(paint.measureText(text, start, end)) + space
        }
    
        override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
            space = Math.round(paint.measureText(charters, 0, charters.length))
            canvas.drawText(text, start, end, x + space, y.toFloat(), paint)
            canvas.drawText(charters, x, y.toFloat(), paint)
        }
        }
    
    }
    

    Uasge:

    editText.transformationMethod = formatter
    
    0 讨论(0)
  • 2020-12-02 12:34

    Follow the instructions in this Answer to format the EditText mask.

    https://stackoverflow.com/a/34907607/1013929

    And after that, you can catch the original numbers from the masked string with:

    String phoneNumbers = maskedString.replaceAll("[^\\d]", "");
    
    0 讨论(0)
  • 2020-12-02 12:36

    I've recently done a similar formatting like 1 (XXX) XXX-XXXX for Android EditText. Please find the code below. Just use the TextWatcher sub-class as the text changed listener : ....

    UsPhoneNumberFormatter addLineNumberFormatter = new UsPhoneNumberFormatter(
                new WeakReference<EditText>(mYourEditText));
        mYourEditText.addTextChangedListener(addLineNumberFormatter);
    

    ...

    private class UsPhoneNumberFormatter implements TextWatcher {
        //This TextWatcher sub-class formats entered numbers as 1 (123) 456-7890
        private boolean mFormatting; // this is a flag which prevents the
                                        // stack(onTextChanged)
        private boolean clearFlag;
        private int mLastStartLocation;
        private String mLastBeforeText;
        private WeakReference<EditText> mWeakEditText;
    
        public UsPhoneNumberFormatter(WeakReference<EditText> weakEditText) {
            this.mWeakEditText = weakEditText;
        }
    
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            if (after == 0 && s.toString().equals("1 ")) {
                clearFlag = true;
            }
            mLastStartLocation = start;
            mLastBeforeText = s.toString();
        }
    
        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            // TODO: Do nothing
        }
    
        @Override
        public void afterTextChanged(Editable s) {
            // Make sure to ignore calls to afterTextChanged caused by the work
            // done below
            if (!mFormatting) {
                mFormatting = true;
                int curPos = mLastStartLocation;
                String beforeValue = mLastBeforeText;
                String currentValue = s.toString();
                String formattedValue = formatUsNumber(s);
                if (currentValue.length() > beforeValue.length()) {
                    int setCusorPos = formattedValue.length()
                            - (beforeValue.length() - curPos);
                    mWeakEditText.get().setSelection(setCusorPos < 0 ? 0 : setCusorPos);
                } else {
                    int setCusorPos = formattedValue.length()
                            - (currentValue.length() - curPos);
                    if(setCusorPos > 0 && !Character.isDigit(formattedValue.charAt(setCusorPos -1))){
                        setCusorPos--;
                    }
                    mWeakEditText.get().setSelection(setCusorPos < 0 ? 0 : setCusorPos);
                }
                mFormatting = false;
            }
        }
    
        private String formatUsNumber(Editable text) {
            StringBuilder formattedString = new StringBuilder();
            // Remove everything except digits
            int p = 0;
            while (p < text.length()) {
                char ch = text.charAt(p);
                if (!Character.isDigit(ch)) {
                    text.delete(p, p + 1);
                } else {
                    p++;
                }
            }
            // Now only digits are remaining
            String allDigitString = text.toString();
    
            int totalDigitCount = allDigitString.length();
    
            if (totalDigitCount == 0
                    || (totalDigitCount > 10 && !allDigitString.startsWith("1"))
                    || totalDigitCount > 11) {
                // May be the total length of input length is greater than the
                // expected value so we'll remove all formatting
                text.clear();
                text.append(allDigitString);
                return allDigitString;
            }
            int alreadyPlacedDigitCount = 0;
            // Only '1' is remaining and user pressed backspace and so we clear
            // the edit text.
            if (allDigitString.equals("1") && clearFlag) {
                text.clear();
                clearFlag = false;
                return "";
            }
            if (allDigitString.startsWith("1")) {
                formattedString.append("1 ");
                alreadyPlacedDigitCount++;
            }
            // The first 3 numbers beyond '1' must be enclosed in brackets "()"
            if (totalDigitCount - alreadyPlacedDigitCount > 3) {
                formattedString.append("("
                        + allDigitString.substring(alreadyPlacedDigitCount,
                                alreadyPlacedDigitCount + 3) + ") ");
                alreadyPlacedDigitCount += 3;
            }
            // There must be a '-' inserted after the next 3 numbers
            if (totalDigitCount - alreadyPlacedDigitCount > 3) {
                formattedString.append(allDigitString.substring(
                        alreadyPlacedDigitCount, alreadyPlacedDigitCount + 3)
                        + "-");
                alreadyPlacedDigitCount += 3;
            }
            // All the required formatting is done so we'll just copy the
            // remaining digits.
            if (totalDigitCount > alreadyPlacedDigitCount) {
                formattedString.append(allDigitString
                        .substring(alreadyPlacedDigitCount));
            }
    
            text.clear();
            text.append(formattedString.toString());
            return formattedString.toString();
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题