Search code examples
androidkotlinkotlin-extension

How to pass a parameter to a extension function in Kotlin


I have an extension function in kotlin to check is it a valid string or not as stated below.

fun EditText.onAfterTextChanged(listener: (String) -> Unit) {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable?) {
            val input = editable?.toString()
            val allowedChars = context.getString(R.string.supported_digits)
            val newValue = replaceInvalidCharacters(input, allowedChars)
            if (newValue != input) {
                setText(newValue)
                setSelection(text.length)
            }
            listener(newValue)
        }

        override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }

        override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
    })
}

private fun replaceInvalidCharacters(value: String?, allowedChars: String): String {
    var finalValue = value ?: ""
    if (finalValue.isNotEmpty()) {
        val lastChar = finalValue.last()
        if (!allowedChars.contains(lastChar, false)) {
            finalValue = finalValue.dropLast(1)
        }
    }
    return finalValue
}

I am using it like:

editText.onAfterTextChanged {
        val length = it.length
        if (length >= 250) {
            activity?.toast(getString(R.string.max_limit_reached))
            return@onAfterTextChanged
        }
}

Here I want to pass allowedChars as a parameter to this extension as there are different strings are there for different EditText's in the application. Like 1 EditText may allow only number's but not +,- and some edit text may allow only alphanumeric, etc. Is there any way to pass a parameter to the extension?


Solution

  • What you can do is update the extension function signature by adding a parameter before the callback function. So, it'll look something like this

    fun EditText.onAfterTextChanged(allowedChars: String, listener: (String) -> Unit) {
        addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(editable: Editable?) {
                val input = editable?.toString()
                val allowedChars = context.getString(R.string.supported_digits)
                val newValue = replaceInvalidCharacters(input, allowedChars)
                if (newValue != input) {
                    setText(newValue)
                    setSelection(text.length)
                }
                listener(newValue)
            }
    
            override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
            }
    
            override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
            }
        })
    }
    

    And you can call it like so:

    editText.onAfterTextChanged("123abc") {
        val length = it.length
        if (length >= 250) {
            activity?.toast(getString(R.string.max_limit_reached))
            return@onAfterTextChanged
        }
    }