https://kotlinlang.org logo
#codereview
Title
# codereview
e

Ellen Spertus

05/09/2022, 1:40 AM
I'm modifying some code that looks like this (middle 8 lines omitted):
Copy code
dialpad_0_holder.setOnClickListener { dialpadPressed('0', it) }
dialpad_9_holder.setOnClickListener { dialpadPressed('9', it) }
If the flag
tremor
is
true
, I would like to call
setOnLongClickListener
instead of
setOnClickListener
. Is it possible to do something like this?
Copy code
val f = if (tremor) RelativeLayout.onLongClickListener else RelativeLayout.onClickListener
dialpad_0_holder.f { dialpadPressed('0', it) }
dialpad_9_holder.f { dialpadPressed('9', it) }
e

ephemient

05/09/2022, 1:49 AM
with other types you would be able to use method references like
Copy code
val f = if (tremor) View::setOnLongClickListener else View::setOnClickListener
f(dialpad_0_holder) { dialpadPressed('0', it) }
but it doesn't work with
View
because the functions here take two different types,
View.OnLongClickListener
versus
View.OnClickListener
✔️ 1
e

Ellen Spertus

05/09/2022, 1:50 AM
Cool! Thank you.
e

ephemient

05/09/2022, 1:52 AM
you could consider
Copy code
val views = listOf(dialpad_0_holder, ..., dialpad_9_holder)
for ((i, view) in views.withIndex()) {
    if (tremor) {
        view.setOnLongClickListener { ddialpadPressed('0' + i, it }
    } else {
        view.setOnClickListener { dialpadPressed('0' + i, it }
    }
}
or
🥇 1
e

Ellen Spertus

05/09/2022, 1:52 AM
Any thoughts on what I'm planning instead?
Copy code
private fun setNumberPress(tremor: Boolean) {
        val children = dialpad_holder.children.toList()
        val digitRange = CharRange('0', '9')
        children.zip(digitRange).forEach { pair ->
            if (tremor) {
                pair.first.setOnLongClickListener { dialpadPressed(pair.second, it); true }
            } else {
                pair.first.setOnClickListener { dialpadPressed(pair.second, it) }
            }
        }
    }
e

ephemient

05/09/2022, 1:53 AM
yes, that is an option
e

Ellen Spertus

05/09/2022, 1:53 AM
What you wrote is much nicer.
e

ephemient

05/09/2022, 1:54 AM
another option would be
Copy code
val views = mapOf(
    dialpad_0_holder to '0',
    ...
)
if (tremor) {
    val listener = View.OnLongClickListener {
        dialpadPressed(views.getValue(it), it)
    }
    for (view in views.keys) view.setOnLongClickListener(listener)
} else {
    // ditto with View.OnClickListener
🙏 1
TBH it's even possible to create a single listener class to use in both the
setOnLongClick
and
setOnClick
cases,
Copy code
val listener = object : View.OnLongClickListener, View.OnClickListener {
    override fun onLongClick(view: View): Boolean = ...
    override fun onClick(view: View)...
}
but I wouldn't bother. if the duplicated code gets too complicated I'd rather pull it out into another function instead that both listener types can call into
e

Ellen Spertus

05/09/2022, 2:01 AM
I don't see how that would work unless there was a 3rd method:
Copy code
fun onAction(view: View) {
    if (tremor) {
        onLongClick(view)
    } else {
        onClick(view)
    }
}
e

ephemient

05/09/2022, 2:05 AM
Copy code
fun View.setClickListener(tremor: Boolean, action: (View) -> Boolean) {
    if (tremor) {
        view.setOnLongClickListener { action() }
    } else {
        view.setOnClickListener { action() }
    }
}
dialpad_0_holder.setOnClickListener(tremor) { dialpadPressed('0', it) }
does create a bunch of lambda objects that then get wrapped in other listeners, but it's fine in practice
✔️ 1
3 Views