使用电话号码格式 NaN 屏蔽 EditText,就像 PhoneNumberUtils 中一样

发布于 2024-10-01 22:43:15 字数 169 浏览 5 评论 0原文

我想让用户在 editText 中输入电话号码,以便在每次用户输入号码时动态更改格式。也就是说,当用户输入最多 4 位数字(例如 7144)时,editText 显示“714-4”。 我希望每当用户输入数字时,editText 就会动态更新为格式 ###-###-####。这怎么办?另外,我正在处理多个 editText。

I want to make user inputted phone number in an editText to dynamically change format every time the user inputs a number. That is, when user inputs up to 4 digits, like 7144, the editText shows "714-4".
I would like the editText to be dynamically updated to format ###-###-#### whenever the user inputs a digit. how can this be done? also, I am handling more than one editTexts.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

公布 2024-10-08 22:43:15

最简单的方法是使用内置的 Android PhoneNumberFormattingTextWatcher

因此,基本上,您可以在代码中获取 EditText 并像这样设置文本观察器...

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

使用 PhoneNumberFormattingTextWatcher 的好处是,它将根据您的区域设置正确格式化您的号码条目。

Easiest way to do this is to use the built in Android PhoneNumberFormattingTextWatcher.

So basically you get your EditText in code and set your text watcher like this...

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

Nice thing about using PhoneNumberFormattingTextWatcher is that it will format your number entry correctly based on your locale.

朱染 2024-10-08 22:43:15

上面的答案是正确的,但它适用于特定国家/地区。如果有人想要这种格式的电话号码(###-###-####)。然后使用:

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 = " "

现在将这一行添加到您的 edittext 的 xml 中

android:inputType="phone"

即可。

已编辑:如果您希望编辑文本长度限制为 10 位数字,请在下面添加行:(

android:maxLength="12"

为 12,因为“-”将占用两次空格)

Above answer is right but it works with country specific. if anyone want such formatted phone number(###-###-####). Then use this:

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

                }
            });

Declare String lastChar = " " in your activity.

Now add this line in xml of your edittext

android:inputType="phone"

That's all.

Edited: If you want your edittext lenght to limit 10 digits add line below also:

android:maxLength="12"

(It is 12 because "-" will take space two times)

冰雪之触 2024-10-08 22:43:15

只需将以下内容添加到电话号码的 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, "-");
                }
            }
        }
    });

Just add the following to EditText for Phone Number to get a formatted phone number(###-###-####)

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, "-");
                }
            }
        }
    });
薄荷港 2024-10-08 22:43:15

Kotlin 中的 Android 动态掩码。这个工作正常并且严格符合电话号码掩码。您可以提供任何您想要的面具。

编辑1:我有一个新版本,可以锁定用户在键盘上键入的不需要的字符。

/**
 * Text watcher allowing strictly a MASK with '#' (example: (###) ###-####
 */
class NumberTextWatcher(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, "")
    }
}

编辑2:单元测试

class NumberTextWatcherTest {

    @Test
    fun phone_number_test() {
        val phoneNumberMask = "(###) ###-####"
        val phoneNumberTextWatcher = NumberTextWatcher(phoneNumberMask)

        val input = StringBuilder()
        val expectedResult = "(012) 345-6789"
        var result = ""

        // mimic typing 10 digits
        for (i in 0 until 10) {
            input.append(i)
            result = mimicTextInput(phoneNumberTextWatcher, result, i.toString()) ?: ""
        }

        Assert.assertEquals(input.toString(), "0123456789")
        Assert.assertEquals(result, expectedResult)
    }

    @Test
    fun credit_card_test() {
        val creditCardNumberMask = "#### #### #### ####"
        val creditCardNumberTextWatcher = NumberTextWatcher(creditCardNumberMask)

        val input = StringBuilder()
        val expectedResult = "0123 4567 8901 2345"
        var result = ""

        // mimic typing 16 digits
        for (i in 0 until 16) {
            val value = i % 10
            input.append(value)
            result = mimicTextInput(creditCardNumberTextWatcher, result, value.toString()) ?: ""
        }

        Assert.assertEquals(input.toString(), "0123456789012345")
        Assert.assertEquals(result, expectedResult)
    }

    @Test
    fun date_test() {
        val dateMask = "####/##/##"
        val dateTextWatcher = NumberTextWatcher(dateMask)

        val input = "20200504"
        val expectedResult = "2020/05/04"
        val initialInputValue = ""

        val result = mimicTextInput(dateTextWatcher, initialInputValue, input)

        Assert.assertEquals(result, expectedResult)
    }

    @Test
    fun credit_card_expiration_date_test() {
        val creditCardExpirationDateMask = "##/##"
        val creditCardExpirationDateTextWatcher = NumberTextWatcher(creditCardExpirationDateMask)

        val input = "1121"
        val expectedResult = "11/21"
        val initialInputValue = ""

        val result = mimicTextInput(creditCardExpirationDateTextWatcher, initialInputValue, input)

        Assert.assertEquals(result, expectedResult)
    }

    private fun mimicTextInput(textWatcher: TextWatcher, initialInputValue: String, input: String): String? {
        textWatcher.beforeTextChanged(initialInputValue, initialInputValue.length, initialInputValue.length, input.length + initialInputValue.length)
        val newText = initialInputValue + input

        textWatcher.onTextChanged(newText, 1, newText.length - 1, 1)
        val editable: Editable = SpannableStringBuilder(newText)

        textWatcher.afterTextChanged(editable)
        return editable.toString()
    }
}

Dynamic Mask for Android in Kotlin. This one is working fine and strictly fitting the phone number mask. You can provide any mask you whish.

EDIT1: I have a new version that locks event the unwanted chars typed by the user on the keyboard.

/**
 * Text watcher allowing strictly a MASK with '#' (example: (###) ###-####
 */
class NumberTextWatcher(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, "")
    }
}

EDIT 2: Unit tests

class NumberTextWatcherTest {

    @Test
    fun phone_number_test() {
        val phoneNumberMask = "(###) ###-####"
        val phoneNumberTextWatcher = NumberTextWatcher(phoneNumberMask)

        val input = StringBuilder()
        val expectedResult = "(012) 345-6789"
        var result = ""

        // mimic typing 10 digits
        for (i in 0 until 10) {
            input.append(i)
            result = mimicTextInput(phoneNumberTextWatcher, result, i.toString()) ?: ""
        }

        Assert.assertEquals(input.toString(), "0123456789")
        Assert.assertEquals(result, expectedResult)
    }

    @Test
    fun credit_card_test() {
        val creditCardNumberMask = "#### #### #### ####"
        val creditCardNumberTextWatcher = NumberTextWatcher(creditCardNumberMask)

        val input = StringBuilder()
        val expectedResult = "0123 4567 8901 2345"
        var result = ""

        // mimic typing 16 digits
        for (i in 0 until 16) {
            val value = i % 10
            input.append(value)
            result = mimicTextInput(creditCardNumberTextWatcher, result, value.toString()) ?: ""
        }

        Assert.assertEquals(input.toString(), "0123456789012345")
        Assert.assertEquals(result, expectedResult)
    }

    @Test
    fun date_test() {
        val dateMask = "####/##/##"
        val dateTextWatcher = NumberTextWatcher(dateMask)

        val input = "20200504"
        val expectedResult = "2020/05/04"
        val initialInputValue = ""

        val result = mimicTextInput(dateTextWatcher, initialInputValue, input)

        Assert.assertEquals(result, expectedResult)
    }

    @Test
    fun credit_card_expiration_date_test() {
        val creditCardExpirationDateMask = "##/##"
        val creditCardExpirationDateTextWatcher = NumberTextWatcher(creditCardExpirationDateMask)

        val input = "1121"
        val expectedResult = "11/21"
        val initialInputValue = ""

        val result = mimicTextInput(creditCardExpirationDateTextWatcher, initialInputValue, input)

        Assert.assertEquals(result, expectedResult)
    }

    private fun mimicTextInput(textWatcher: TextWatcher, initialInputValue: String, input: String): String? {
        textWatcher.beforeTextChanged(initialInputValue, initialInputValue.length, initialInputValue.length, input.length + initialInputValue.length)
        val newText = initialInputValue + input

        textWatcher.onTextChanged(newText, 1, newText.length - 1, 1)
        val editable: Editable = SpannableStringBuilder(newText)

        textWatcher.afterTextChanged(editable)
        return editable.toString()
    }
}
江湖正好 2024-10-08 22:43:15

我的脚本,示例取自此处此处的说明


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

My script, example taken from here description here


<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;
        }
    }
};
弥繁 2024-10-08 22:43:15

上述解决方案没有考虑退格,因此当您在键入后删除一些数字时,格式往往会混乱。下面的代码纠正了这个问题。

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

The above solutions do not take backspace into consideration so when you delete some numbers after typing, the format tends to mess up. Below code corrects this issue.

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) { }
    });
酒与心事 2024-10-08 22:43:15

此代码允许您使用掩码### - ### - ####(不含空格)输入电话号码,并且这里还修复了删除电话数字的问题:

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"/>

This code allow you enter phone number with mask ### - ### - #### (without spaces) and also here is fixed the issue with deletion of phone digits:

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

Layout:

<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"/>
燃情 2024-10-08 22:43:15

这是我的解决方案

如何在 Activity/Fragment 中运行(fe in onViewCreated):

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

exampleIdField.editText?.addTextChangedListener(exampleIdValidator)

Validatior 类:

    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

Here is my solution

How run in Activity/Fragment (f.e in onViewCreated):

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

exampleIdField.editText?.addTextChangedListener(exampleIdValidator)

Validatior class:

    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 = " "
        }
    }

Layout:

    <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" />

Result is:

XX XXX XXX XXX
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文