Maybe a noob question. But what is the replacement...
# compose
s
Maybe a noob question. But what is the replacement of Android's Selector(Drawable State List) in Compose? I want to make a button that looks differently under certain conditions.
Pressed
,
enabled
,
disabled
,
focused
,
hovered
, etc.
👀 2
s
Short answer is a this is replaced by composable functions and parameters.
z
Pressed/Focused/Hovered are, I think, done with something called “indications”, and Enabled/Disabled are “emphasis”.
s
@Sean McQuillan [G] Should I manually track different states and update state and appearence accordingly?
s
Depending on what you're doing – you could make a slot parameter to handle drawing the background based on the state, as an example:
Copy code
@Composable
fun SelectorBackground(currentState: /*...*/, content: @Composable () -> Unit) {
   ... logic to select background ...
}
s
Or old good
<selector/>
api going to be reinvented in compose style?
s
In the simplest form yea – hoist the relevant states to the place where they're updated/consumed then change the drawing code based on the state
I don't think I've seen any exploration of trying to create a workalike API, but I'd be interesting to hear what people have tried.
s
Hm... The solution is a bit bulky but I'll try. Thanks 👍
Yea it's a bit less encapsulated than the selector API – I'd definitely be interested in seeing what you come up with
(and will noodle on it as well 🙂 )
😃 1
s
@Sean McQuillan [G] What type of data could represent the state? Does old good
android.graphics.Drawable
still suitable or Compose has its own types alike to the
Drawable
?
It will work with clickable out of the box, for example
You can see it's usage in the material button which uses it to implement the ripple
s
lovely
s
If you're not building a library-like composable, simply swapping the indication on a
Button
is probably the simplest way to get custom behavior (reading a bunch of code to try to answer this question 🙂 )
You can swap the ripple for some other drawing code
Backing up – what do you want to specialize based on the state?
s
Just a custom button background, maybe not solid colors but some pictures
For instance a 9.patch with a saturated shadow
s
Ah ok – then in that case yea I'm leading you down the wrong route 🙂
So there's no single Drawable type in compose that handles images/colors as a single type etc and the material Button can only handle background color
s
What logic should I follow when I do something custom in Compose? I mean whether it should be a Composable function or a Modifier to achieve the desired effect on a UI. In other words when I must choose to make a Composable function and when a Modifier? To make something custom.
s
So, starting from the Material button, you can either draw a background over the color using a modifier, or you can make a composable that draws it's own background.
As to which to choose – in this case it depends, if you're defining the core button style for your app then I'd make a composable, if it's just a 1-off styling choice then a modifier works
Modifiers applied to a composable are kind of like inline XML attributes on Views
They're good for styling a single location
A new composable function is more similar to defining a reusable view style in this decision tree
s
Sounds convincing. Much appreciated for your time and help. Thank you.
s
Thanks for your question – I'll keep thinking about this problem too. I hadn't considered selectors previously. And sorry for going down the path of trying to implement a library-level Button alternative for a bit at the beginning there 🙂. I'd love to see what you land at for this as you explore.
🤗 2
l
It is not currently implemented in Material components, but in the future components like Button will accept an
InteractionState
parameter - which allows you to hoist and read this state to customize how the Button appears. For example, to customize the button based on whether it is pressed would look something like:
Copy code
val interactionState = remember { InteractionState() }

Button(
    interactionState = interactionState,
    backgroundColor = if (Interaction.Presesd in interactionState) Color.Red else Color.Blue
) {...}
Unfortunately this hasn't landed yet, so it isn't really easy to do this right now
❤️ 2
For example, animating the elevation between default / pressed states recently landed in: https://android-review.googlesource.com/c/platform/frameworks/support/+/1407037
👍 3