android format edittext to display spaces after every 4 characters

前端 未结 12 1664
傲寒
傲寒 2020-12-10 13:27

Android - I want to get a number input from the user into an EditText - it needs to be separated by spaces - every 4 characters. Example: 123456781234 -> 1234 5678 1234

相关标签:
12条回答
  • 2020-12-10 13:32

    Simple Answer

        YourEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                int len=s.toString().length();
    
                if (before == 0 && (len == 4 || len == 9 || len == 14 ))
                    YourEditText.append(" ");
            }
    
            @Override
            public void afterTextChanged(Editable s) {
    
    
            }
        });
    
    0 讨论(0)
  • 2020-12-10 13:33

    If someone still looking for answer, check format-edit-text library

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            final FormatEditText editText1 = findViewById(R.id.edit_text_1);
            editText1.setFormat("---- ---- ---- ----");
        }
    }
    

    Reference https://stackoverflow.com/a/59742478/1679946

    0 讨论(0)
  • 2020-12-10 13:34

    I have created a class that encapsulates the given behavior.

    /**
     * Custom [TextWatcher] class that appends a given [separator] for every [interval].
     */
    abstract class SeparatorTextWatcher(
        private val separator: Char,
        private val interval: Int
    ) : TextWatcher {
    
        private var dirty = false
        private var isDelete = false
    
        override fun afterTextChanged(editable: Editable?) {
            if (dirty) return
    
            dirty = true
            val text = editable.toString().handleSeparator()
            onAfterTextChanged(text)
            dirty = false
        }
    
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            // Empty
        }
    
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            isDelete = before != 0
        }
    
        private fun String.handleSeparator(): String {
            val stringBuilder = StringBuilder(this)
    
            if (length > 0 && length.rem(interval + 1) == 0) {
                if (isDelete) {
                    stringBuilder.deleteCharAt(length - 1)
                } else {
                    stringBuilder.insert(length - 1, separator)
                }
            }
    
            return stringBuilder.toString()
        }
    
        /**
         * Subclasses must implement this method to get the formatted text.
         */
        abstract fun onAfterTextChanged(text: String)
    }
    

    Here's a snippet on how to use it:

    editText.addTextChangedListener(object : SeparatorTextWatcher(' ', 4) {
                override fun onAfterTextChanged(text: String) {
                    editText.run {
                        setText(text)
                        setSelection(text.length)
                    }
                }
            })
    
    0 讨论(0)
  • Assuming that you know the final length of the String, you could implement a TextWatcher this way:

    override fun setUp(view: View?) {
    
        editText.addTextChangedListener(object : TextWatcher{
            override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
            }
    
            override fun onTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {
                if(p2 == 0 && (p0.length == 4 || p0.length == 9 || p0.length == 14))
                    editText.append(" ")
            }
    
            override fun afterTextChanged(p0: Editable?) {
            }
        })
    

    You just add a space each 4-digits block. p2 == 0 is to assure the user is not deleting, otherwise he/she would get stock.

    The code is in Kotlin, You can do it exactly the same way in Java.

    0 讨论(0)
  • 2020-12-10 13:43

    cleaner version of @Ario's answer which follows the DRY principle:

    private int prevCount = 0;
    private boolean isAtSpaceDelimiter(int currCount) {
        return currCount == 4 || currCount == 9 || currCount == 14;
    }
    
    private boolean shouldIncrementOrDecrement(int currCount, boolean shouldIncrement) {
        if (shouldIncrement) {
            return prevCount <= currCount && isAtSpaceDelimiter(currCount);
        } else {
            return prevCount > currCount && isAtSpaceDelimiter(currCount);
        }
    }
    
    private void appendOrStrip(String field, boolean shouldAppend) {
        StringBuilder sb = new StringBuilder(field);
        if (shouldAppend) {
            sb.append(" ");
        } else {
            sb.setLength(sb.length() - 1);
        }
        cardNumber.setText(sb.toString());
        cardNumber.setSelection(sb.length());
    }
    
    ccEditText.addTextChangedListener(new TextWatcher() { 
        @Override 
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
        } 
    
        @Override 
        public void onTextChanged(CharSequence s, int start, int before, int count) {
    
        } 
    
        @Override 
        public void afterTextChanged(Editable s) {
            String field = editable.toString();
            int currCount = field.length();
    
            if (shouldIncrementOrDecrement(currCount, true)){
                appendOrStrip(field, true);
            } else if (shouldIncrementOrDecrement(currCount, false)) {
                appendOrStrip(field, false);
            }
            prevCount = cardNumber.getText().toString().length(); 
        } 
    }); 
    
    0 讨论(0)
  • 2020-12-10 13:47

    I searched lot for this here are the complete code in kotlin for card

      yourEditText.addTextChangedListener(object : TextWatcher {
            private val TOTAL_SYMBOLS = 19 // size of pattern 0000-0000-0000-0000
            private val TOTAL_DIGITS = 16 // max numbers of digits in pattern: 0000 x 4
            private val DIVIDER_MODULO =
                5 // means divider position is every 5th symbol beginning with 1
            private val DIVIDER_POSITION =
                DIVIDER_MODULO - 1 // means divider position is every 4th symbol beginning with 0
            private val DIVIDER = ' '
            override fun beforeTextChanged(
                s: CharSequence,
                start: Int,
                count: Int,
                after: Int
            ) { // noop
            }
    
            override fun onTextChanged(
                s: CharSequence,
                start: Int,
                before: Int,
                count: Int
            ) { // noop
            }
    
            override fun afterTextChanged(s: Editable) {
                if (!isInputCorrect(s, TOTAL_SYMBOLS, DIVIDER_MODULO, DIVIDER)) {
    
                    var repl = buildCorrectString(
                            getDigitArray(s, TOTAL_DIGITS),
                    DIVIDER_POSITION,
                    DIVIDER
                    )
    
                    yourEditText.clearFocus();
                    yourEditText.setText(repl);
                   yourEditText.requestFocus();
                    yourEditText.setSelection(repl!!.length);
    
                }
            }
    
            private fun isInputCorrect(
                s: Editable,
                totalSymbols: Int,
                dividerModulo: Int,
                divider: Char
            ): Boolean {
                var isCorrect =
                    s.length <= totalSymbols // check size of entered string
                for (i in 0 until s.length) { // check that every element is right
                    isCorrect = if (i > 0 && (i + 1) % dividerModulo == 0) {
                        isCorrect and (divider == s[i])
                    } else {
                        isCorrect and Character.isDigit(s[i])
                    }
                }
                return isCorrect
            }
    
            private fun buildCorrectString(
                digits: CharArray,
                dividerPosition: Int,
                divider: Char
            ): String? {
                val formatted = StringBuilder()
                for (i in digits.indices) {
                    if (digits[i] != '\u0000') {
                        formatted.append(digits[i])
                        if (i > 0 && i < digits.size - 1 && (i + 1) % dividerPosition == 0) {
                            formatted.append(divider)
                        }
                    }
                }
                return formatted.toString()
            }
    
            private fun getDigitArray(s: Editable, size: Int): CharArray {
              val digits = CharArray(size)
                var index = 0
                var i = 0
                while (i < s.length && index < size) {
                    val current = s[i]
                    if (Character.isDigit(current)) {
                        digits[index] = current
                        index++
                    }
                    i++
                }
                return digits
            }
        })
    }
    
    0 讨论(0)
提交回复
热议问题