julioromano
06/24/2021, 1:19 PM@Composable
APIs, is it preferable to have a default onClick
param as an empty lambda (onClick: () -> Unit = {}
) or as a nullable function (onclick: (() -> Unit)? = null
)? Are there any pros and cons?albertosh
06/24/2021, 1:27 PMBryan Herbst
06/24/2021, 1:28 PMonClick
as a default seems strange- it implies that your Composable requires handling click behavior, but offers doing nothing as a default. If I think about this in the context of a Button
for example, I expect clicking the button would produce a ripple or other indication when I tap it, but that just wouldn’t do anything. That doesn’t sound like expected behavior.
On the other hand, making the onClick
nullable implies that handling clicks is optional. A good example of this type of API design decision in action is Checkbox
, which offers a nullable onCheckedChange
. Checkbox only adds the selectable()
Modifier when this parameter is not null, so it doesn’t handle clicks at all when onCheckedChange
is null.
Short version: your choice here implies behavior for the component, and you should consider what correct behavior for your component is, including what’s required vs. what’s not.julioromano
06/24/2021, 1:54 PMonClick: () -> Unit = {}
=> onClick is required
2. onclick: (() -> Unit)? = null
=> onClick is optional
But since in case 1 onClick is required, why having a default value at all? Doesn’t the = {}
add confusion?
It seems sort of… Yeah this parameter is required but you don’t have to pass it in…Albert Chang
06/24/2021, 2:06 PMAlexandre Elias [G]
06/25/2021, 1:18 AMAlexandre Elias [G]
06/25/2021, 1:33 AMAlexandre Elias [G]
06/25/2021, 1:37 AMval clickable = if (onClick != null) { Modifier.clickable(...) } else { Modifier }
... `modifier.then(clickable)`(as opposed to the shorter way modifier.clickable(onClick ?: {}, ...)
). That way, not only will you get a slight performance improvement, but more importantly it will send the right signals to accessibilityjulioromano
06/25/2021, 8:44 AMSurface
in beta09: it’s got two different @Composables with either no onClick
at all or a non-null one.
Since I needed an optional onClick in my custom Composable (which uses Surface internally) I had to use the version of Surface without onClick and then place a Box inside it and apply the onClick modifier to the Box:
modifier = Modifier
.fillMaxSize()
.run {
if (onClick == null) this
else clickable(onClick = onClick)
}
Alexandre Elias [G]
06/25/2021, 5:12 PMButton
did it this way. However, we found a problem with this approach: the strong Compose convention is to put passed-in modifier
parameter on the outermost Layout
, but given that the Box
is inside the Surface
, either this convention must be violated, or a testTag
that's passed in will appear not clickableAlexandre Elias [G]
06/25/2021, 5:17 PMSurface
itself and instead directly chain the elevation, shadow, clip modifiers, B) conditionally use one Surface
overload or the other by storing the "content" lambda in a val
instead of following the usual concise last-lambda styleAlexandre Elias [G]
06/25/2021, 5:42 PMjulioromano
06/28/2021, 11:39 AM