Skip to content

Conversation

@ksokolovskyi
Copy link
Contributor

@ksokolovskyi ksokolovskyi commented Oct 10, 2025

Fixes #166485

Description

  • Updates CupertinoSwitch thumb to snap to the sides on drag
  • Updates CupertinoSwitch to emit vibration not when drag starts, but when the dragged thumb crosses the middle point
BEFORE AFTER
before.mov
after.mov

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: cupertino flutter/packages/flutter/cupertino repository labels Oct 10, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the CupertinoSwitch to snap to the sides during a drag and adjusts the haptic feedback to trigger only when the thumb crosses the midpoint. The implementation looks correct and aligns with the behavior shown in the videos. The addition of a new test for the snapping behavior is great. However, I've found a few issues in the existing tests that were modified, mainly around brittle assertions that check for exact animation values during a transition. I've also suggested a simplification for a test helper to improve clarity and correctness. Overall, good changes to improve the user experience of the switch.

@ksokolovskyi ksokolovskyi force-pushed the update-cupertino-switch-behavior branch from 7403fe6 to 666b05e Compare October 10, 2025 10:21
@victorsanni victorsanni self-requested a review October 10, 2025 18:22
Copy link
Contributor

@victorsanni victorsanni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this fix. I was playing around with the native switch, and I see that the switch visually toggled when dragged ~75% of the track length:

native.switch.mov

In this PR, the switch visually toggles when dragged 50% of the track length:

pr.switch.mov

Can you add a video comparing with native side-by-side in the PR description?

@ksokolovskyi
Copy link
Contributor Author

Hi @victorsanni, thank you for taking a look at this PR and providing such valuable information regarding the native iOS switch behavior.

I've investigated how the UISwitch behaves and updated this PR accordingly. The following screen recording compares the updated CupertinoSwitch (top) with a native UISwitch (bottom), both overlaid with a 10% grid.

switch_comparison.mov

As the video demonstrates, the new logic better matches the native behavior:

  1. Commit Threshold: The switch requires a drag of ~70% of the track width to commit to the new state. In the video, the drag starts at the ~20% mark and snaps "on" at the ~90% mark.
  2. Reverse Threshold: While the drag is still active, the switch will not revert to its original state until the user drags back to the ~20% position (relative to the start of the drag). In the video, after the switch snaps "on," it only snaps back "off" when the drag returns to the ~40% mark (which is 20% start position + 20% reverse threshold).

The latest change adds the constants _kDragCommitThreshold (0.7) and _kDragReverseThreshold (0.2) to control this behavior.

The comparison demo repository is available here: https://github.com/ksokolovskyi/cupertino_switch_comparison

@victorsanni
Copy link
Contributor

LGTM. Requesting a review from others who have worked on CupertinoSwitch sometime in the past.

Copy link
Contributor

@MitchellGoodwin MitchellGoodwin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as well!

: _kDragCommitThreshold;
final double effectiveThreshold = widget.value ? -threshold : threshold;

final bool currentDragValue = _dragDelta >= effectiveThreshold;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think this gets a little confusing on which "drag value" means what at a glance. currentDragValue may be better named to something like "newDragValue".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the feedback! I've renamed it in the latest commit.

@dkwingsmt dkwingsmt added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 10, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Nov 10, 2025
Merged via the queue into flutter:master with commit 7947aef Nov 11, 2025
76 checks passed
IvoneDjaja pushed a commit to IvoneDjaja/flutter that referenced this pull request Nov 22, 2025
…76825)

Fixes flutter#166485

## Description

- Updates `CupertinoSwitch` thumb to snap to the sides on drag
- Updates `CupertinoSwitch` to emit vibration not when drag starts, but
when the dragged thumb crosses the middle point

| BEFORE | AFTER |
| - | - |
| <video alt="before"
src="https://github.com/user-attachments/assets/467f0a3c-ab6a-40c0-a0fe-6b1ff835bbb0"
/> | <video alt="after"
src="https://github.com/user-attachments/assets/9bc21bdc-e8a3-4626-8155-1d90614a72fa"
/> |

## Pre-launch Checklist

- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [X] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [X] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [X] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Victor Sanni <[email protected]>
mboetger pushed a commit to mboetger/flutter that referenced this pull request Dec 2, 2025
…76825)

Fixes flutter#166485

## Description

- Updates `CupertinoSwitch` thumb to snap to the sides on drag
- Updates `CupertinoSwitch` to emit vibration not when drag starts, but
when the dragged thumb crosses the middle point

| BEFORE | AFTER |
| - | - |
| <video alt="before"
src="https://github.com/user-attachments/assets/467f0a3c-ab6a-40c0-a0fe-6b1ff835bbb0"
/> | <video alt="after"
src="https://github.com/user-attachments/assets/9bc21bdc-e8a3-4626-8155-1d90614a72fa"
/> |

## Pre-launch Checklist

- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [X] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [X] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [X] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Victor Sanni <[email protected]>
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
…76825)

Fixes flutter#166485

## Description

- Updates `CupertinoSwitch` thumb to snap to the sides on drag
- Updates `CupertinoSwitch` to emit vibration not when drag starts, but
when the dragged thumb crosses the middle point

| BEFORE | AFTER |
| - | - |
| <video alt="before"
src="https://github.com/user-attachments/assets/467f0a3c-ab6a-40c0-a0fe-6b1ff835bbb0"
/> | <video alt="after"
src="https://github.com/user-attachments/assets/9bc21bdc-e8a3-4626-8155-1d90614a72fa"
/> |

## Pre-launch Checklist

- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [X] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [X] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [X] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Victor Sanni <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CupertinoSwitch should not allow holding in a mid-toggle state

4 participants