refactor(design-system): rework on SwipeableRow to include Dismiss, Reveal and Reset behaviours; ditch out from M3 implementation#10679
Conversation
There was a problem hiding this comment.
I tested this on different screen sizes and it doesn't feel as polished as the current implementation. I played with the threshold value and based on the screen size the revealed content is easily cut. Or in landscape you need to swipe large distances to trigger the actions.
When swiping the current implementation had a threshold and visual guide before the action is fired. Which is neat from my point of view.
I couldn't get "Swipe to Reveal with Auto reset" working for "Both directions". While other actions worked.
While testing the swipe functionality completely stopped working 2 -> multiple (updated) times and only after navigating away (Atoms) and back (Molecules) it started to work again. The logs contained nothing that would indicate what is failing. I also had the effect that some stopped working while other swipes where still functio
When doing wild swipes with auto reset enabled and keep on swiping multiple times in different directions (especially on the version with both directions) it acts out, trying to animate to a closed state being interrupted by another swipe in the other direction and trying to keep up processing all the swipe gestures and eventually triggering a lot of end state events and inconsistent end states as not always the last swipe wins. Doing the same with our current version keeps working.
| */ | ||
| @Composable | ||
| private fun RowScope.SwipeableRowBackgroundContent( | ||
| private fun rememberAccessibilityActions( |
There was a problem hiding this comment.
You need to turn on TalkBack, but I guess it isn't working as I expected. I will investigate that too.
There was a problem hiding this comment.
I forgot to set up the accessibility actions in the UI Catalog, but I will take care of that.
To test the functionality, please follow these steps:
- Enable TalkBack.
- Tap on the SwipeableRow.
- Tap three times on the screen.
- Select the "Actions" option and double-tap to open it.
- Choose the action you want to test and double-tap to activate it.
There was a problem hiding this comment.
I always hate having to pull up the talkback actions menu, but I will say, this does work better for accessibility than our current implementation on the Message List, which doesn't expose the swipe actions to the user.
There was a problem hiding this comment.
It does feel like a set size might be better than a screen percentage. Without it, landscape would have to swipe very far, and narrower screens might not reveal all the text for the action under the item until it's well past the threshold. Might be cleaner to do a set amount.
There was a problem hiding this comment.
I see your point, thanks for sharing the images, it helps a lot to understand better!!
But do we want them to be able to customize that?
I don't see harm on allowing users to customize the triggering threshold. I have seen many complaints about the sensitivity of the swipe action and defining a sweet spot for that is really difficult. Letting then customize it would be helpful.
I assume the area revealed under the swipeable row is an interaction element that we'd want to control the padding, sizing, etc on. If the ratio's not just right for an item under the row, they may not know what an item is doing as they swipe on it. By not making it a ratio, we can make the swipe distance, and therefore the size of the item that displays under the row, constant. That ensures it's the right shape, the right length to reveal the text, and the same swipe distance regardless of screen size.
You are right! I guess the problem here is that I'm linking the swipe action trigger threshold with the reveal background element size, which will create that issue. I guess I need to have a different logic for swipe to dismiss, which the background will always be the size of the row, and the swipe to reveal, which will have a fixed background size.
The question is: should the swipe action trigger threshold be tied to the size of the background element or also a fixed size?
Let's say we set the swipe action trigger threshold to a fixed size, e.g. 100dp, but the reveal background element's size is 50dp. Then, users would need to swipe the whole background element's size to reveal it. Is that what we want?
With percentage, we could let the percentage be calculated with the background element's size, but that could create a sensitivity issue as well...
Besides that, the swipe distance itself could change between orientations. Even if we define different ratios for different orientations, we can't guarantee the same swipe distance each time.
I'm not sure if it is important to guarantee the same swipe distance, tbh. I think it is more important to guarantee how easy is to trigger the action rather than how far I need to swipe (same distance).
Additionally, we need to remember that as we use dp, a fixed size will vary depending on user's device resolution.
We could still keep this independent of the item below it, just allow the length of the swipe to be a hard size that the implementation can decide.
Answered above.
Also, what if we eventually implement a short/far swipe thing? Some apps have different options depending on whether or not you swiped only far enough to reveal the first item or if you kept swiping to do something else. It could be mark read for a short swipe and reply for a full swipe, something like that.
That might be a good idea, but I would keep for the future. Currently we only support one swipe action per direction.
And then there's the concern that we may have more than just swipeable items on the message list. Would the same ratio for the message list make sense elsewhere?
I don't think so... I can't see a use case for that, tbh.
Thanks for all the inputs! Let me know your thoughts and let's keeping doing these kinds of discussion! I feel we will bring a better UX with this!
There was a problem hiding this comment.
I'm not sure if it is important to guarantee the same swipe distance, tbh. I think it is more important to guarantee how easy is to trigger the action rather than how far I need to swipe (same distance).
Additionally, we need to remember that as we use dp, a fixed size will vary depending on user's device resolution.
More we could define the swipe distance to be limited by the size of the item that it's revealing. When we design the item below it, we'd set it to either a length that design says. Honestly, at the end of the day, I don't think this is an engineering decision anyway. This should be something the design team weighs in on. It might not be a bad idea to ensure the swipeable item could have a limit based on screen size or a hard pixel limit
There was a problem hiding this comment.
@laurelterlesky, @Alecaddd, here is the thread! I asked GPT to create a TL;DR, but feel free to read all the comments:
TL;DR:
The thread is debating whether swipe actions should use a percentage-based threshold or a fixed/limited swipe distance.
The main concern with percentages is that the revealed action area can feel inconsistent across screen sizes and orientations, which may make the UI look less polished or hide functionality.
Rafael agrees that the current approach is coupling the trigger threshold too closely to the revealed background size, and suggests dismiss and reveal may need different logic.
The discussion ends with a soft consensus that this should probably be guided by design, with swipe distance constrained by the size of the revealed action — or at least capped — rather than using one ratio everywhere.
There was a problem hiding this comment.
Swipe actions by their own nature are a quick entry point to trigger repeated action, a convenient and more faster way to do things rather than accessing menus.
With that in mind, if we make the threshold based on %, it'll become very inconvenient to do long swipes when in landscape mode or tablet.
My recommendation is to define a fixed value for the threshold.
Based on my tests a comfortable distance on mobile portrait orientation is around 150px.
We shouldn't worry too much about needing to reveal the whole text of the action underneath because that can drastically change based on translations and it won't always meet our size expectations.
The important things are:
- When the threshold is met, the background color of the action changes (as it already happens)
- If the user doesn't let go and drags back the swipe action nothing gets triggered. This allows users to drag as much as they want to read the text underneath without triggering anything.
- Acceleration is important as some users expect the swipe action to pass the threshold naturally if the swipe is quick.
Bonus
We might consider having different px distance for different resolutions, but that's for later and I would start with the simple and consistent implementation first.
There was a problem hiding this comment.
Thank you for sharing that! I've changed the SwipeBehaviour threshold to a fixed size instead of a percentage. The default threshold size is now 150.dp, but you can customize it.
Bonus
We might consider having different px distance for different resolutions, but that's for later and I would start with the simple and consistent implementation first.
For this PR, we are focusing on the creation of design system components. The adjustments for different resolutions will be addressed in a separate branch. The last screen recording I shared demonstrated the current component already integrated, but it was intended just as an example.
The "revealed content being cut" is because of how the behind element is drawn. I believe it is being cut off only in the "swipe to reveal", but the Swipe component shouldn't be responsible for how their slot composables are drawn. Regarding the "you need to swipe large distances to trigger the actions", the threshold is based on a % of the actual width available to swipe. We could change to be an actual value, or both. How do you feel about this? I will also add an input to let you play with the threshold directly from the ui-catalog
I'm not sure what kind of visual guide you are talking about, so I will leave a few videos here:
Could you please point me to the visual guide you were referring to?
Have you tried to swipe it before swiping the others? Might be related to the next issue you mentioned. Here is a screen record of it working: Screen.Recording.2026-03-18.at.11.31.42.AM.mov
I was able to reproduce this issue. I will investigate the reason.
I will investigate that too, thanks for bringing this |
8488120 to
9271f14
Compare
|
@wmontwe, I've made several updates to the animations and addressed issues related to accessibility, behaviour, and gestures that I identified. Additionally, I've added a slider to the UI-Catalogue to allow for threshold adjustments. I also wanted to give you a heads-up about the Saver implementation: During testing, I noticed that when swiping and rotating the screen, the state was saved but only for one orientation. There is a bug in the Please let me know if you want any other change. |
25e633c to
4a70e9c
Compare
…eveal and Reset behaviours; ditch out from M3 implementation
…d control and snackbar feedback
…nd dismiss transition
…expose swipe progress allowing dynamic background color and swipe progress handling
- Changed the `threshold` property in `SwipeBehaviour` from a percentage-based `Float` to a fixed `Dp` value. - Updated `SwipeableRowState` to calculate relative percentage thresholds dynamically based on layout width and screen density. - Updated the UI catalog to reflect these changes with a DP-based slider.
4a70e9c to
7b1cb5c
Compare
Part of #10554.
SwipeBehavioursealed interface, which encapsulates swipe behaviour (threshold, animation, auto-reset, and disabled state) and replaces the previous threshold-based approach. This allows for more flexible and reusable swipe configurations. (SwipeBehaviour.kt)SwipeBehaviourobject and a set of swipe directions, replacing the old per-direction threshold and enabling/disabling flags. This simplifies usage and improves composability. (SwipeableRowItems.kt)These changes make swipeable row components more flexible, accessible, and easier to use throughout the codebase.