web-dev-qa-db-ja.com

PhoneNumberUtilsのようにEditTextを電話番号形式NaNでマスクする

EditTextでユーザーが入力した電話番号に、ユーザーが番号を入力するたびに動的に形式を変更させるようにしたいのですが。つまり、ユーザーが7144のように4桁まで入力すると、editTextは「714-4」を示します。ユーザーが数字を入力するたびに、editTextが###-###-####の形式に動的に更新されるようにしたいと思います。これはどのように行うことができますか?また、1つ以上のeditTextを処理しています。

25
eunique0216

これを行う最も簡単な方法は、組み込みのAndroid PhoneNumberFormattingTextWatcher を使用することです。

したがって、基本的にはコードでEditTextを取得し、テキストウォッチャーを次のように設定します...

EditText inputField = (EditText) findViewById(R.id.inputfield);
inputField.addTextChangedListener(new PhoneNumberFormattingTextWatcher());

PhoneNumberFormattingTextWatcherを使用する良い点は、ロケールに基づいて番号エントリを正しくフォーマットすることです。

75
brockoli

上記の答えは正しいですが、国ごとに機能します。そのような形式の電話番号が必要な場合(###-###-####)。次にこれを使用します:

etPhoneNumber.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    int digits = etPhoneNumber.getText().toString().length();
                    if (digits > 1)
                        lastChar = etPhoneNumber.getText().toString().substring(digits-1);
                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    int digits = etPhoneNumber.getText().toString().length();
                    Log.d("LENGTH",""+digits);
                    if (!lastChar.equals("-")) {
                        if (digits == 3 || digits == 7) {
                            etPhoneNumber.append("-");
                        }
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            });

宣言String lastChar = " "あなたの活動。

次に、この行を編集テキストのxmlに追加します

Android:inputType="phone"

それで全部です。

編集済み: edittextの長さを10桁に制限する場合は、以下の行も追加します。

Android:maxLength="12"

(「-」は2回スペースを取るので12です)

9
Rahul Sharma

私のスクリプト、ここからの例 ここの説明


<Android.support.design.widget.TextInputLayout
    Android:id="@+id/numphone_layout"
    app:hintTextAppearance="@style/MyHintText"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"

    Android:layout_marginTop="8dp">

    <Android.support.design.widget.TextInputEditText
        Android:id="@+id/edit_text_numphone"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:theme="@style/MyEditText"
        Android:digits="+() 1234567890-"
        Android:hint="@string/hint_numphone"
        Android:inputType="phone"
        Android:maxLength="17"
        Android:textSize="14sp" />
</Android.support.design.widget.TextInputLayout>

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 TextInputEditText phone = (TextInputEditText) findViewById(R.id.edit_text_numphone);
 //Add to mask
    phone.addTextChangedListener(textWatcher);
}


   TextWatcher textWatcher = new TextWatcher() {
    private boolean mFormatting; // this is a flag which prevents the  stack overflow.
    private int mAfter;

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // nothing to do here..
    }

    //called before the text is changed...
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        //nothing to do here...
        mAfter  =   after; // flag to detect backspace..

    }

    @Override
    public void afterTextChanged(Editable s) {
        // Make sure to ignore calls to afterTextChanged caused by the work done below
        if (!mFormatting) {
            mFormatting = true;
            // using US or RU formatting...
            if(mAfter!=0) // in case back space ain't clicked...
            {
                String num =s.toString();
                String data = PhoneNumberUtils.formatNumber(num, "RU");
                if(data!=null)
                {
                    s.clear();
                    s.append(data);
                    Log.i("Number", data);//8 (999) 123-45-67 or +7 999 123-45-67
                }

            }
            mFormatting = false;
        }
    }
};
2
Aleksandr K

次を電話番号のEditTextに追加して、フォーマットされた電話番号を取得します(###-###-####)

Phone.addTextChangedListener(new TextWatcher() {

        int length_before = 0;

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            length_before = s.length();
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (length_before < s.length()) {
                if (s.length() == 3 || s.length() == 7)
                    s.append("-");
                if (s.length() > 3) {
                    if (Character.isDigit(s.charAt(3)))
                        s.insert(3, "-");
                }
                if (s.length() > 7) {
                    if (Character.isDigit(s.charAt(7)))
                        s.insert(7, "-");
                }
            }
        }
    });
1
chzahid

上記のソリューションではバックスペースが考慮されていないため、入力後に数字をいくつか削除すると、フォーマットが混乱する傾向があります。以下のコードはこの問題を修正します。

phoneNumberEditText.addTextChangedListener(new TextWatcher() {

        int beforeLength;

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            beforeLength = phoneNumberEditText.length();
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            int digits = phoneNumberEditText.getText().toString().length();
            if (beforeLength < digits && (digits == 3 || digits == 7)) {
                phoneNumberEditText.append("-");
            }
        }

        @Override
        public void afterTextChanged(Editable s) { }
    });
1
Rancho Jr.

Androidの動的マスク。これは正常に機能し、電話番号マスクに厳密に適合しています。どのマスクでも指定できます。

編集:ユーザーがキーボードで入力した不要な文字をイベントにロックする新しいバージョンがあります。

/**
 * Text watcher allowing strictly a MASK with '#' (example: (###) ###-####
 */
class PhoneNumberTextWatcher(private var mask: String) : TextWatcher {
    companion object {
        const val MASK_CHAR = '#'
    }

    // simple mutex
    private var isCursorRunning = false
    private var isDeleting = false

    override fun afterTextChanged(s: Editable?) {
        if (isCursorRunning || isDeleting) {
            return
        }
        isCursorRunning = true

        s?.let {
            val onlyDigits = removeMask(it.toString())
            it.clear()
            it.append(applyMask(mask, onlyDigits))
        }

        isCursorRunning = false
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        isDeleting = count > after
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}

    private fun applyMask(mask: String, onlyDigits: String): String {
        val maskPlaceholderCharCount = mask.count { it == MASK_CHAR }
        var maskCurrentCharIndex = 0
        var output = ""

        onlyDigits.take(min(maskPlaceholderCharCount, onlyDigits.length)).forEach { c ->
            for (i in maskCurrentCharIndex until mask.length) {
                if (mask[i] == MASK_CHAR) {
                    output += c
                    maskCurrentCharIndex += 1
                    break
                } else {
                    output += mask[i]
                    maskCurrentCharIndex = i + 1
                }
            }
        }
        return output
    }

    private fun removeMask(value: String): String {
        // extract all the digits from the string
        return Regex("\\D+").replace(value, "")
    }
}
0
Maxime Claude

このコードでは、マスク###-###-####(スペースなし)を使用して電話番号を入力できます。また、電話番号の削除に関する問題が修正されています。

editText.addTextChangedListener(new TextWatcher() {
            final static String DELIMITER = "-";
            String lastChar;

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                int digits = editText.getText().toString().length();
                if (digits > 1)
                    lastChar = editText.getText().toString().substring(digits-1);
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                int digits = editText.getText().length();
                // prevent input dash by user
                if (digits > 0 && digits != 4 && digits != 8) {
                    CharSequence last = s.subSequence(digits - 1, digits);
                    if (last.toString().equals(DELIMITER))
                        editText.getText().delete(digits - 1, digits);
                }
                // inset and remove dash
                if (digits == 3 || digits == 7) {
                    if (!lastChar.equals(DELIMITER))
                        editText.append("-"); // insert a dash
                    else
                        editText.getText().delete(digits -1, digits); // delete last digit with a dash
                }
                dataModel.setPhone(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {}
        });

レイアウト:

<EditText
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:imeOptions="actionDone"
            Android:textAlignment="textStart"
            Android:inputType="number"
            Android:digits="-0123456789"
            Android:lines="1"
            Android:maxLength="12"/>
0

これが私の解決策です

アクティビティ/フラグメントでの実行方法(つまり、onViewCreatedで):

//field in class
private val exampleIdValidator by lazy { ExampleIdWatcher(exampleIdField.editText!!) }

exampleIdField.editText?.addTextChangedListener(exampleIdValidator)

検証クラス:

    import Android.text.Editable
    import Android.text.TextWatcher
    import Android.widget.EditText

    class ExampleIdWatcher(exampleIdInput: EditText) : TextWatcher {

        private var exampleIdInput: EditText = exampleIdInput

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(userInput: CharSequence?, start: Int, before: Int, count: Int) {
            if (userInput!!.isNotEmpty() && !areSpacesCorrect(userInput)) {

                val stringTextWithoutWhiteSpaces: String = userInput.toString().replace(" ", "")

                val textSB: StringBuilder = StringBuilder(stringTextWithoutWhiteSpaces)

                when {
                    textSB.length > 8 -> {
                        setSpacesAndCursorPosition(textSB, 2, 6, 10)
                    }
                    textSB.length > 5 -> {
                        setSpacesAndCursorPosition(textSB, 2, 6)
                    }
                    textSB.length > 2 -> {
                        setSpacesAndCursorPosition(textSB, 2)
                    }
                }
            }
        }

        override fun afterTextChanged(s: Editable?) {
        }

        private fun setSpacesAndCursorPosition(textSB: StringBuilder, vararg ts: Int) {
            for (t in ts) // ts is an Array
                textSB.insert(t, SPACE_CHAR)
            val currentCursorPosition = getCursorPosition(exampleIdInput.selectionStart)
            exampleIdInput.setText(textSB.toString())
            exampleIdInput.setSelection(currentCursorPosition)
        }

        private fun getCursorPosition(currentCursorPosition: Int): Int {
            return if (EXAMPLE_ID_SPACE_CHAR_CURSOR_POSITIONS.contains(currentCursorPosition)) {
                currentCursorPosition + 1
            } else {
                currentCursorPosition
            }
        }

        private fun areSpacesCorrect(userInput: CharSequence?): Boolean {
            EXAMPLE_ID_SPACE_CHAR_INDEXES.forEach {
                if (userInput!!.length > it && userInput[it].toString() != SPACE_CHAR) {
                    return false
                }
            }
            return true
        }

        companion object {
            private val EXAMPLE_ID_SPACE_CHAR_INDEXES: List<Int> = listOf(2, 6, 10)
            private val EXAMPLE_ID_SPACE_CHAR_CURSOR_POSITIONS: List<Int> = EXAMPLE_ID_SPACE_CHAR_INDEXES.map { it + 1 }
            private const val SPACE_CHAR: String = " "
        }
    }

レイアウト:

    <com.google.Android.material.textfield.TextInputEditText
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:digits=" 0123456789"
        Android:inputType="numberPassword"
        Android:maxLength="14"
        tools:text="Example text" />

結果は次のとおりです。

XX XXX XXX XXX
0
Bartosz Luczak