Reputation: 2019
I use Kotlin and practice lambda expression.
In normal, View.setOnClickListener
can convert to lambda
Normal
textView.setOnClickListener(object :View.OnClickListener{
override fun onClick(p0: View?) {
}
})
Lambda
textView.setOnClickListener { }
then I copy the source code and just rename the function
class CustomView{
fun setCustomOnClickListener(l: CustomOnClickListener) {
throw RuntimeException("Stub!")
}
}
interface CustomOnClickListener {
fun customOnClick(var1: View?)
}
and I create my customView but it can't be convert to lambda
val myCustomView = CustomView()
myCustomView.setCustomOnClickListener(object :CustomOnClickListener{
override fun customOnClick(var1: View?) {
}
})
// can't convert to
// myCustomView.setCustomOnClickListener{
//
// }
Can anyone explains why and how to convert to lambda expression?
Thanks!!
Upvotes: 1
Views: 2135
Reputation: 1450
I think as of the date this question was posted, it wasn't possible to do so in Kotlin. But now it's available in Kotlin starting from version 1.4 with functional interfaces.
Here is an example on how to do it:
// Define your interface here (note the 'fun' modifier prior to 'interface')
fun interface CustomOnClickListener {
fun customOnClick(view: View)
}
// Call your custom interface in the form of a Lambda
myCustomView.setCustomOnClickListener { view ->
// Implement your logic here
}
For more information about functional interfaces, you can visit the following link https://kotlinlang.org/docs/fun-interfaces.html#sam-conversions
Upvotes: 0
Reputation: 121
I have converted spinner's OnItemSelectedListener using lambda function as parameter check it out where I only care about onItemSelected method.
import android.view.View
import android.widget.AdapterView
class SelectionListener(val lis:(parent: AdapterView<*>?, view: View?, position: Int, id: Long) -> Unit) : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
lis(parent,view, position, id)
}
override fun onNothingSelected(parent: AdapterView<*>?) { }
}
Now attach it to your spinner in activity / fragment
my_spinner.onItemSelectedListener = SelectionListener { parent, view, position, id ->
//do your work after selection
}
Upvotes: 0
Reputation: 1429
What you're asking about is called a SAM conversion (converting an actual interface implementation into a lambda). SAM stands for "single abstract method."
You can only do SAM conversions for Java interfaces (which View.OnClickListener
is). But your CustomOnClickListener
is a Kotlin interface. Therefore, you cannot do a SAM conversion. You must implement it with object : CustomOnClickListener { override . . . }
. You cannot use a lambda.
Straight from the Kotlin docs:
note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported
What you could do if you wanted to keep your code concise is, instead of creating interface CustomOnClickListener
you could do
typealias CustomOnClickListener = (View?)->Unit
then your setter function would be the same. Your invoking function would then be this.myListener(myView)
or you could even use the experimental inline class instead:
inline class CustomOnClickListener(val customOnClick: (View?)->Unit)
then your setter would be
fun setListener(listener: CustomOnClickListener) { this.listener = listener }
and your invoking code would be
listener.customOnClick(someView)
Edit Some more fleshed-out code:
class CustomView{
var listener: CustomOnClickListener? = null
fun setCustomOnClickListener(l: CustomOnClickListener) {
listener = l
}
}
And then you can do this:
inline class CustomOnClickListener(val customOnClick: (View?)->Unit)
and then your custom view:
val myCustomView = CustomView()
myCustomView.setCustomOnClickListener(CustomOnClickListener({ it: View? ->
// whatever your listener is supposed to do with the view, it goes here
}))
Or, instead of inline class
(which is still considered an experimental feature in Kotlin), you can do this:
typealias CustomOnClickListener = (View?)->Unit
and then your custom view:
val myCustomView = CustomView()
myCustomView.setCustomOnClickListener { it: View? ->
// whatever your listener is supposed to do with the view, it goes here
}
Here is an example.
Upvotes: 5
Reputation: 1184
Just like @user1713450 said, this concept is called SAM Conversion and this works for only Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
To explain your code above:
The object
keyword can be used to create objects of an anonymous class known as anonymous objects. They are used if you need to create an object of a slight modification of some class or interface without declaring a subclass for it.
The correct syntax should be:
interface CustomOnClickListener {
fun customOnClick(var1: View?)
}
//Use the interface in your class
class CustomView{
fun setCustomOnClickListener(l: CustomOnClickListener) {
throw RuntimeException("Stub!")
}
}
To use the CustomView
class:
val customView = CustomView()
customView.setCustomOnClickListener(object: CustomOnClickListener{
override fun customOnClick(var1: View?) {
}
})
Upvotes: 0