Does anybody know why material 3 replaced `interfa...
# compose
m
Does anybody know why material 3 replaced `interface`s with `class`es for
ButtonColors
,
TextFieldColors
, etc.? It’ll limit user-space options now
😞 3
c
I’m not entirely sure, but my guess would be to help enforce Stability of those classes for better performance. Also there’s probably not much of a good use case for letting them be interfaces when the typical way to change colors in Compose is through the Theme’s colors, or by passing parameters to the functions like
ButtonDefaults.buttonColors()
s
The previous model was quite flawed, as it forced
@Composable
functions and state objects. Using a class to store those values is much better for performance, as 95% of cases can be handled by providing the color as parameter. What's the use-case that it restricted for you?
m
That could have been achieved without removing the
interface
though, with a non-
@Composable
alternative to
ButtonDefaults.buttonColors()
, couldn’t it? That should yield the same performance? I’m currently designing a custom theme system and we’re trying to decide between the
interface
and
class
approach for us. The scenario we have in mind would be to set up custom animated transitions between the colors for arbitrary states or even to add additional states on any
Interaction
which are more complex than what `Indication`s can offer. For example, changing the border color on hover. For that purpose, we’d be passing an
InteractionSource
into all color state factories, like it is already done in most of
TextFieldColors
, even if not used by default. With a class, this option isn’t there anymore.
s
I am not sure you'd be able to collect an interaction source without a composable function though
m
No need, that would happen lazily as it already does in the color state factory, and those are also still there in Material 3:
The `Button`/`TextField` etc. call those internally on `ButtonColors`/`TextFieldColors` etc.
Those used to be part of the
interface
as well
s
Yeah, so we don't really wanna do that
you collect and update interactions at composition time, while creating extra states. this is heavier for compositions and invalidates everything whenever state changes
m
But this still happens in the material 3 implementation
s
correct, we are slowly phasing this out 🙂
m
Interesting. Any idea on what the new API will look like? It would make little sense for us to adopt this pattern if it’s about to change anyway. In fact, we had the same concerns about redundant collections and states but we thought it must be fine if Material 3 is still doing that 😅
s
It's likely that user-facing API is going to be more rigid, the same as you see in
ButtonColors
, as Material already handles many interactions internally. I assume that you are not really interested in some material aspects, so for you it might be easier to just customize
Surface
+ text or even
Box
+ text. Ideally, you'd avoid creating and memoizing intermediate states and just have state for color that is later used to invalidate draw pass
m
you collect and update interactions at composition time, while creating extra states.
I’m trying to understand this all the way. Am I right that the actual issue is that the color state will be read during composition, while passing it to the corresponding modifier as a parameter? Because setting up some state on initial composition is the only way to do that, isn’t it? And such a problem could be avoided with a draw modifier that takes a lambda for determining its inputs, including the color?
s
My comment is more about launching many effects and remembering many states for things that can be just a flow chain / suspend function Technically, if you are animating colors you probably want to
drawRect
in a draw modifier instead of invalidating composition with modifier
background
. If you are switching between discrete values, it should be fine though.
m
Understood, thanks for the thorough explanation!