Based on NathanOliver's and enneract's code I wrote, in kotlin, a variation that insertes a dot when one is deleted.
class IpAddressEditText : AppCompatEditText {
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
private fun init() {
// phone input type to show the numeric keyboard in all kinds of devices
inputType = InputType.TYPE_CLASS_PHONE
// restrict the input of the characters specified in string bellow
keyListener = DigitsKeyListener.getInstance("0123456789.")
// InputFilter decides what can be typed
filters = arrayOf(InputFilter { source, start, end, dest, dstart, dend ->
if (end > start) {
val inputString = dest.toString()
val substring = inputString.substring(0, dstart) + source.subSequence(start, end) + inputString.substring(dend)
if (!substring.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?".toRegex())) {
// do not allow the input of:
// segments with more than 3 characters and less than 1;
// segments != 4;
return@InputFilter ""
} else {
val splits = substring.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (i in splits.indices) {
// don't allow a segment with a value more than 255
if (Integer.valueOf(splits[i]) > 255) {
return@InputFilter ""
}
}
}
}
null
})
// TextWatcher notifies what was typed
addTextChangedListener(object : TextWatcher {
var isDeleting = false
var lastCount = 0
override fun afterTextChanged(editable: Editable) {
if (!isDeleting) {
val inputString = editable.toString()
val segmentList = inputString.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val lastSegment = segmentList[segmentList.size - 1]
// each segment of the ip can have max size of 3 characters and a max value of 255
if (lastSegment.length == 3 || lastSegment.length == 2 && Integer.parseInt(lastSegment) > 25) {
// add a dot automatically if the conditions met
editable.append('.')
return
}
} else {
// add a dot in the same position where it was deleted
editable.insert(selectionStart, ".")
}
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
isDeleting = lastCount >= count
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// do nothing
}
})
}
}