im trying to make an imput to be limited to a range of numbers using the TextWatcher
and force the min and max if user try to go out of range. Works almost as expected but on a delete, allowing a visually empty text. How can i avoid that?
inputVal.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) { //s=""
var curVal = s.toString().toIntOrNull()?:5 //curVal=5
if (curVal < 5){
curVal = 5
s.replace(0,s.length,"5") <- problem here, not replacing cuz s.length=0
}else if (curVal >50){
curVal = 50
s.replace(0,s.length,"50")
}
//some other things to do based on 'curVal'
}})
CodePudding user response:
If s will be empty, the curVal will be 5.
So it won't trigger any of the conditions.
Maybe try with:
if (curVal <= 5)
CodePudding user response:
You can change as per your preference; we only need to use source and dest only.
source returns the new input entered in edittext or empty if pressed backspace dest returns prev input which in buffer already
Let's say if I enter 6 first time in edittext source returns 6 and dest returns empty as no input in buffer for first time, if enter 7 next then source will return 7 but dest will return 6. Using this we can check the limit.
class InputRangeFilter(val mMin: Int, val mMax: Int) : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
val finalValue = (dest.toString().trim() source.toString().trim()).toInt()
return if (source?.isEmpty() == true && dest?.isEmpty() == true) {
""
} else if (finalValue in (mMin 1) until mMax) {
null // keep original
} else {
if ((!TextUtils.isEmpty(source) && source.toString().trim().toInt() < mMin)
&& finalValue < mMax
) {
if (source.toString().toInt() == 0) {
""
} else {
source
}
} else {
""
}
}
}
}
Usage:
binding.edtText.filters = arrayOf(InputRangeFilter(5, 100))