I'm having a difficult time trying how to figure out how to create a callback in Kotlin using lambdas. I have a custom TextInputEditText and I want to implement a function that the activity can call when text changes.
Here is my custom EditText:
class EditTextEx : TextInputEditText, TextWatcher {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// Call the callback onTextAvailable with the EditText's text (s.toString)
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
}
In my activity I want to have a callback that gets called when the onTextChanged event gets called. The callback in the custom control sends only the text back to the client. So in my activity, I want something like this:
editText.onTextAvailable(text -> do something )
In addition to the solution by @EpicPandaForce, there are a couple other solutions. If you want to stick with using a class as you've shown in your example, then you can do this:
class EditTextEx : TextInputEditText, TextWatcher {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var mOnTextWatcherCallback: (m: String) -> Unit = {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (mOnTextWatcherCallback != null)
mOnTextWatcherCallback(s.toString())
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
fun onTextChange(callback: (text: String) -> Unit) {
mOnTextWatcherCallback = callback
}
}
Then in your activity create a function:
fun onTextChange(text: String) {
// Do something with the text.
}
And then setup your callback as follows:
my_edittext.onTextChange(::onTextChange)
This solution allows you to re-use the same onTextChange function for other controls that want to use it as well.
If you prefer to use an interface to define the callback, do this:
class EditTextEx : TextInputEditText, TextWatcher {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var mOnTextWatcherCallback: ITextWatcher? = null
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (mOnTextWatcherCallback != null)
mOnTextWatcherCallback!!.onTextChanged(s.toString())
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
fun onTextChange(callback: ITextWatcher) {
mOnTextWatcherCallback = callback
}
}
Then in your activity, create the callback as follows:
val textChangeHandler = object: ITextWatcher {
override fun onTextChanged(text: String) {
var t = text
}
}
And then setup your callback for your edittext controls as follows:
my_edittext.onTextChange(textChangeHandler)
It's actually quite easy to do, look:
inline fun EditText.onTextChanged(crossinline onTextChange: (String) -> Unit): TextWatcher {
val textWatcher = object: TextWatcher {
override fun afterTextChanged(editable: Editable) {
onTextChange(editable.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
}
this.addTextChangeListener(textWatcher)
return textWatcher
}
Now you can call
editText.onTextChanged { text -> /* do something */ }
Try something like this:
fun getEditTextChange(editText: EditText, onTextChange: (String) -> Unit){
val tw = object: TextWatcher {
private var region = Locale.getDefault().language
override fun afterTextChanged(s: Editable?) {
onTextChange.invoke(s.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
}
editText.addTextChangedListener(tw)
}
Hope it helps