I’m thinking about an alternative way to augment c...
# compose
o
I’m thinking about an alternative way to augment component appearance in response to
interactionSource
.
Indication
only allows to draw something, but not change how component renders itself, e.g. pseudo-3d button actually moving slightly when pressed, or a component shaking a bit if attempted to interact with it, doing component-specific hover effects, etc. I wonder if anyone already gave it a thought and have ideas/approaches on how to design it?
z
I have been worried about that a bit. Drawing-only is such a limited way of visually responding to interaction, it seems weird that something sounding as generic as “Indication” would only support that one way.
You could do some stuff with canvas transforms
3
It would be nice if
Indication
returned a
Modifier
or something though imo (to be fair, i haven’t actually done much with this part of the api, but it would be nice to not have to implement things like borders from scratch when there are so many nice modifiers)
o
I was thinking more in the way of setting up some “styles” for components, like
ButtonStyle
specifying how a button is being presented (colors, corner radius, etc) and then being able to specify a “style-set” for a button with different styles for different states. This way component defines a “protocol” for how to configure it in different states/interactions/transitions, and you could define some “theme” for your app (especially, games and desktop apps). But I didn’t settle on something specific yet and would like to hear different opinions.
a
with the exception of explicitly reusing modifiers, all of the things listed are things that you could do with the drawing scope 🤔
we've taken a less is more approach to theming with compose UI; Android and other systems across different form factors tend to go through a major design system overhaul about every 3-5 years and the "general" protocols set up to be expressive enough for the previous overhaul usually fail to properly express the next one without introducing new elements that aren't orthogonal to the old. Over a few of these the system gets very complex and hard to reason about, and we'd like to try to avoid that.
💯 1
👆 1
The design library approach is intended to mitigate this, where you toss out the whole theming system with the old design system's library when a new one replaces it, rather than letting it accumulate cruft.
👆 1
Trying to keep one
Button
component that encompasses every potentially styleable attribute of the concept of "button" historically wasn't worth the complexity it introduced in both understandability at any given snapshot in time and maintainability over time.
💯 1
👆 1
k
The approach I'm taking with Radiance (for Swing) and Aurora (for Compose Desktop) is state-based. There are component states - https://github.com/kirill-grouchnikov/radiance/blob/sunshine/docs/substance/skins/componentstates.md (rollover, selected, pressed, but also any combination of these). A color scheme - https://github.com/kirill-grouchnikov/radiance/blob/sunshine/docs/substance/skins/colorschemes.md - is a collection of colors that can be associated with a specific part of a specific component under a specific state - https://github.com/kirill-grouchnikov/radiance/blob/sunshine/docs/substance/skins/colorschemeassociationkinds.md. So a checkbox, for example, would have color scheme association kinds for the check mark, the inner fill of the box, and the border of the box. This gives the flexibility to finely control the visuals of the checkbox under different states (rollover, rollover selected, pressed, pressed selected, etc). A color scheme bundle - https://github.com/kirill-grouchnikov/radiance/blob/sunshine/docs/substance/skins/colorschemebundles.md - is used to define these mapping for one visual area (title pane, toolbar, status bar, etc). Which then allows using https://github.com/kirill-grouchnikov/radiance/blob/sunshine/docs/substance/painters/decoration.md - decoration painters to further highlight such areas
Transitions between states happen at two levels, if you will. Say you move the mouse over a button, then click down, then release, then move the mouse away. The button goes from enabled to rollover to rollover pressed to rollover selected pressed to rollover selected to selected state. Simplifying a bit, let's only look at one color just for the background. If enabled is grey, rollover is yellow, rollover pressed is orange, rollover selected pressed is red, rollover selected is dark orange and selected is dark yellow.
At any given point in time, the color animation can move between any number of these states - depending how fast you're moving the mouse and clicking.
So it goes from gray (enabled) to yellow (rollover), but then halfway through it goes to orange (rollover pressed). You can't just switch gray->yellow to yellow->orange. That will be a visible jump. It still needs to account for however much amount of grey was there as it starts moving towards orange.
And if you move the mouse away and press up halfway through that transition, the button goes back to enabled / grey. So there are two "contributions" of grey now, the original one, and the new target one.
I consider each such state to be an attractor. At any point in time, a component can be in a transition that involves multiple attractors, each one contributing a certain amount of itself to the current state of that component. That contribution determines how much of the color / colors of that state are used to paint that component (different parts, like border, fill, arrow, checkmark, etc).
Separating it into two levels - attractors and the visual representation of attractors contributions should also make it a bit easier to reason about how to represent those contributions. Maybe it's just colors. Maybe it's the press ripple. Maybe it's build a 3D representation of a component "surface" and distorting that for specific attractors (press)
a
totally agree on separating those things; InteractionSource/Indication is an expression of that too.
in particular, using the event stream rather than states in InteractionSource fixed a lot of conceptual troubles that manifested in some very complicated implementations trying to reconstruct the original event stream