how to put # character before the word in edittext?
what I want : I wanna put # character before the every word written in edit text
every word starts with #
for example :
#hello #world #hi
Try this TextWatcher.
class SharpWordsTextWatcher: TextWatcher {
private var addSharp: Boolean = false
private var isEmpty = false
override fun afterTextChanged(s: Editable) {
if(addSharp) {
s.insert(s.length - 1, "#")
}
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
isEmpty = s.isEmpty() || s.last() == ' '
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
addSharp = isEmpty && s.last() != ' ' && count != 0
}
}
And add this to your EditText.
myEditText.addTextChangedListener(SharpWordsTextWatcher())
Related
I want to insert a space every 2 digits when inputting a string in edittext
For example, if you have the string 'abcdefghijk'
I want the edittext to come out like this 'ab cd ef gh ij k'
What should I do? thank you
The best way of doing this is to do something similar that this answer is doing.
For your code it would mean something like this:
class SpacedTextWatcher(private val editText: EditText) : TextWatcher {
override fun afterTextChanged(s: Editable?) {
editText.removeTextChangedListener(this)
val initialLength = editText.text.length
val v = s.toString().chunked(2).joinToString(" ")
val cp = editText.selectionStart
editText.setText(v)
val endLength = editText.length()
val selection = (cp + (endLength - initialLength))
if (selection > 0 && selection <= editText.text.length) {
editText.setSelection(selection)
} else {
editText.setSelection(editText.text.length - 1)
}
editText.addTextChangedListener(this)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
}
This answer is not handling special use-cases where there is a space in the string or anything else, but I think you can figure out the rest yourself. Just make sure you register this textWatcher on the editText you want to format.
Here is the exact solution what you want:
fun editTextSetContentMemorizeSelection(editText: EditText, charSequence: CharSequence) {
var selectionStart = editText.selectionStart
var selectionEnd = editText.selectionEnd
editText.setText(charSequence.toString())
if (selectionStart > charSequence.toString().length) {
selectionStart = charSequence.toString().length
}
if (selectionStart < 0) {
selectionStart = 0
}
if (selectionEnd > charSequence.toString().length) {
selectionEnd = charSequence.toString().length
}
if (selectionEnd < 0) {
selectionEnd = 0
}
editText.setSelection(selectionStart, selectionEnd)
}
fun formatStrWithSpaces(can: CharSequence): String? {
val sb = StringBuffer()
for (i in 0 until can.length) {
if (i != 0 && i % 2 == 0) {
sb.append(' ')
}
sb.append(can[i])
}
return sb.toString()
}
In your onCreate or where ever you want to use textwatcher:
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
val origin = s.toString().replace(" ".toRegex(), "")
val formatStr = formatStrWithSpaces(origin)
if (s.toString() != formatStr) {
editTextSetContentMemorizeSelection( editText, formatStr!!)
if (before == 0 && count == 1 && formatStr!![ editText.getSelectionEnd() - 1] == ' ') {
editText.setSelection(editText.getSelectionEnd() + 1)
}
}
}
override fun afterTextChanged(s: Editable) {}
})
Here is the Source of this answer. You can also check.
i am trying to get a phone number from editText in my project. the problem i'm having;
1 -> the first digit should not be 0.
2 -> unfortunately but I can't delete spaces..
The number format I want to get; (555) 555 55 55
The stage my code has come to;
class PhoneNumberMask(val editText: EditText) : TextWatcher {
var phoneNumber: String = ""
var isRunning: Boolean = false
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
if (isRunning || s.length == 15) {
return
}
isRunning = true
phoneNumber = when (s.length) {
0 -> "test"
1 -> "($s"
4 -> "$s) "
9 -> "$s "
12 -> "$s "
else -> s.toString()
}
editText.setText(phoneNumber).also { editText.setSelection(phoneNumber.length) }
isRunning = false
}
}
I think your strategy is going to have troubles when the user moves the cursor to the middle of the text field, backspaces, or tries to paste text. What I would try is filtering to only digits each time it's changed and insert parentheses/spaces for the whole string of digits every time. Then put the cursor back where they had it. You can figure out where the cursor should be more easily from onTextChanged than from afterTextChanged.
Something like this:
class PhoneNumberMask(val editText: EditText) : TextWatcher {
private var isRunning: Boolean = false
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (isRunning) {
return
}
var cursorPosition = start + count
val digits = s.filter(Char::isDigit)
.dropWhile { it == '0' }
.take(10)
cursorPosition -= s.take(cursorPosition).run {
count { !it.isDigit() } + filter(Char::digit).takeWhile { it == '0' }.count()
}
val output = StringBuilder(digits)
fun punctuate(position: Int, punctuation: String) {
if (digits.length > position) {
output.insert(position, punctuation)
if (cursorPosition > position) {
cursorPosition += punctuation.length
}
}
}
punctuate(8, " ")
punctuate(6, " ")
punctuate(3, ") ")
punctuate(0, "(")
isRunning = true
editText.setText(output)
editText.setSelection(cursorPosition.coerceAtMost(output.length))
isRunning = false
}
override fun afterTextChanged(s: Editable) {
}
}
I have a numberDecimal EditText (codeInput) in my app, and I want the output to be multiplied by a double (tipPercent) as it is being typed, so I can display it to a textView (totalText). I tried this code:
costInput.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int,
count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
totalText.setText(s * tipPercent)
}
})
when I use this, however, I get this error:
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public inline operator fun BigDecimal.plus(other: BigDecimal): BigDecimal defined in kotlin
public inline operator fun BigInteger.plus(other: BigInteger): BigInteger defined in kotlin
what can I do to fix this? Thanks.
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
val input = Integer.parseInt(s.toString())
val res = input * tipPercent
totalText.setText("$res")
}
Try this:
costInput.doAfterTextChanged { text ->
val cost = text.toString().toDoubleOrNull()
totalText.text = if(cost == null) "" else totalText.text = "${cost * tipPercent}"
}
This will take care of invalid input in costInput.
I'm trying to hide error on a text input layout after the user solves the error but I am not sure how to do that, given that the function afterTextChanged doesn't seem to work with it. How can I do this?
This is the part I'm talking about:
loginViewModel.loginFormState.observe(this, Observer {
val loginState = it ?: return#Observer
// disable login button unless fields are valid
binding.btnLogin.isEnabled = loginState.isDataValid
if (loginState.emailError != null) {
binding.etEmail.error = getString(loginState.emailError)
}
if (loginState.passwordError != null) {
binding.tfPassword.error = getString(loginState.passwordError)
}
})
binding.etEmail.afterTextChanged {
loginViewModel.loginDataChanged(
binding.etEmail.text.toString(),
binding.etPassword.text.toString()
)
}
binding.etPassword.afterTextChanged {
loginViewModel.loginDataChanged(
binding.etEmail.text.toString(),
binding.etPassword.text.toString()
)
}
private fun TextInputEditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
afterTextChanged.invoke(editable.toString())
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
})
Even if the user writes the password correctly and they can click on a button I have, the error is still there, how can I make it go away?
I guess your error lies in those lines:
if (loginState.emailError != null) {
binding.etEmail.error = getString(loginState.emailError)
}
Now imagine emailError was "some error" once and now is null. The bindings' text will not be set again, so it's still "some error". To fix this mistake replace it with:
binding.etEmail.error = if(loginState.emailError != null){
getString(loginState.emailError)
} else {
null
}
Do the same for your passwordError
you can use setError method and pass null as argument. from documentation
Sets an error message that will be displayed below our EditText. If
the error is null, the error message will be cleared.
you can call this method in afterTextChanged as
textInputEditText.addTextChangedListener (object: TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
override fun afterTextChanged(s: Editable?) {
textInputLayout.error = null
}
})
I want to create mask for credit card mask for edittext in format like [0000] [0000] [0000] [0000], but not user should delete whitespaces manually
For example:
"4444_4444_4"
"444_4444_"
How to implement deleting of whitespace " " automatically?
https://github.com/RedMadRobot/input-mask-android
Try this. Hope it will help. (Kotlin example)
class CreditCardFormattingTextWatcher : TextWatcher {
private var etCard: EditText? = null
private var isDelete: Boolean = false
constructor(etcard: EditText) {
this.etCard = etcard
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
isDelete = before != 0
}
override fun afterTextChanged(s: Editable) {
val source = s.toString()
val length = source.length
val stringBuilder = StringBuilder()
stringBuilder.append(source)
if (length > 0 && length % 5 == 0) {
if (isDelete)
stringBuilder.deleteCharAt(length - 1)
else
stringBuilder.insert(length - 1, " ")
etCard?.setText(stringBuilder)
etCard?.setSelection(etCard?.text?.length ?: 0)
}
}
}