我可以通过功能参数发送扩展功能吗?

时间:2016-08-19 02:32:50

标签: android kotlin kotlin-extension

我在下面有一些扩展功能。

fun EditText.setEmailValidationListener(): TextWatcher {
    val textWatcher = object : TextWatcher {
        override fun beforeTextChanged(text: CharSequence?, start: Int, count: Int, after: Int) { }
        override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) { }
        override fun afterTextChanged(text: Editable?) { validateEmail() }

        private fun validateEmail(): Boolean {
            if (validateEmailFormat(showError = false)) {
                getParentInputLayout()?.isErrorEnabled = false
                return true
            }
            return false
        }
    }
    addTextChangedListener(textWatcher)

    return textWatcher

}

fun EditText.setPasswordValidationListener(): TextWatcher {
    val textWatcher = object : TextWatcher {
        override fun beforeTextChanged(text: CharSequence?, start: Int, count: Int, after: Int) { }
        override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) { }
        override fun afterTextChanged(text: Editable?) { validateEmpty() }

        private fun validatePasswordText(): Boolean {
            if (validateEmptyText(showError = false)) {
                getParentInputLayout()?.isErrorEnabled = false
                return true
            }
            return false
        }
    }

    addTextChangedListener(textWatcher)

    return textWatcher
}

fun EditText.validateEmailFormat(showError: Boolean = true): Boolean 
{
    // Do something checking the Email
    return false
}

fun EditText.validatePasswordText(showError: Boolean = true): Boolean     
{
    // Do something checking the Password
    return false
}

private fun EditText.getParentInputLayout(): TextInputLayout? {
    if (parent is TextInputLayout) {
        return parent as TextInputLayout
    }
    return null
}

setEmailValidationListenersetPasswordValidationListener都是相同的,除了它们分别使用的验证函数,即validateEmailFormatvalidatePasswordFormat

所以我计划将两个函数公共代码重构为一个常用函数,如下所示

fun EditText.setupTextChangeListener(validatorFunc : (showError: Boolean) -> Boolean): TextWatcher {
    val textWatcher = object : TextWatcher {
        override fun beforeTextChanged(text: CharSequence?, start: Int, count: Int, after: Int) { }
        override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) { }
        override fun afterTextChanged(text: Editable?) { validateEmpty() }

        private fun validateEmpty(): Boolean {
            if (validatorFunc(false)) {
                getParentInputLayout()?.isErrorEnabled = false
                return true
            }
            return false
        }
    }

    addTextChangedListener(textWatcher)

    return textWatcher
}

...它基本上只是将validationFunc作为参数发送给它。

但是,我无法找到将EditText.validateEmailFormatEditText.validatePasswordFormat发送到validationFunc函数参数的任何方式。

我怎么能实现这个目标?

1 个答案:

答案 0 :(得分:6)

一些理论

扩展功能的签名比先看一下要复杂一点。扩展需要对该类的对象进行一些引用才能对其进行操作。

实际上是扩展方法

fun EditText.validateEmailFormat(showError: Boolean = true): Boolean

反编译成普通的旧java后,看起来像这样:

public static final boolean validateEmailFormat(@NotNull EditText $receiver, boolean showError)

因为(几乎)不可能改变已编译的Java类。因此,Kotlin(很可能是其他具有扩展方法概念的语言)使用静态方法,第一个参数是扩展类的接收者,以使其工作。

回到商家

您的validateEmailFormat实际上属于EditText.(Boolean) -> Boolean类型,同时属于(EditText, Boolean) -> Boolean类型。所以你需要做两件事之一:

首先,您可以EditText.setupTextChangeListener接受validatorFunc作为EditText.(Boolean) -> Boolean(EditText, Boolean) -> Boolean而不是(Boolean) -> Boolean

或者你不要在EditText中扩展fun EditText.validateEmailFormat(Boolean)并使其成为普通的Kotlin函数,例如像这样fun validateEmailFormat(String, Boolean)

由于您正在广泛使用扩展功能,我认为第一个选项是正确的解决方案。