Skip to content

Migrate focus_node.unfocus.0.dart to use RadioGroup#183979

Merged
auto-submit[bot] merged 6 commits into
flutter:masterfrom
ValentinVignal:example/api/migrate-focus-node-unfocus-to-use-radio-group
May 12, 2026
Merged

Migrate focus_node.unfocus.0.dart to use RadioGroup#183979
auto-submit[bot] merged 6 commits into
flutter:masterfrom
ValentinVignal:example/api/migrate-focus-node-unfocus-to-use-radio-group

Conversation

@ValentinVignal
Copy link
Copy Markdown
Contributor

Fixes #179088

Pre-launch Checklist

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

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: focus Focus traversal, gaining or losing focus labels Mar 21, 2026
Copy link
Copy Markdown
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 successfully migrates the focus_node.unfocus.0.dart example to use the RadioGroup widget, which simplifies the code by centralizing the radio button state management. The corresponding test file focus_node.unfocus.0_test.dart has been partially updated to reflect the new focus behavior, but the second test case appears to have been missed and is now likely failing due to changes in focus traversal. This second test should be updated to correctly navigate the radio group using arrow keys. I've also included a minor suggestion to remove a redundant setState call in the example code.

Comment thread examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart
@ValentinVignal
Copy link
Copy Markdown
Contributor Author

Changing to the radio group changes (breaks?) the current behavior. The unselected radio cannot be focused anymore. It forces me to change the 1st test, and the 2nd test fails.

  • Is it intended?
  • Or is there something to implement to keep the original behavior?
  • Or is it revealing a bug with RadioGroup ?

@AbdeMohlbi
Copy link
Copy Markdown
Contributor

AbdeMohlbi commented Mar 21, 2026

Changing to the radio group changes (breaks?) the current behavior. The unselected radio cannot be focused anymore. It forces me to change the 1st test, and the 2nd test fails.

  • Is it intended?
  • Or is there something to implement to keep the original behavior?
  • Or is it revealing a bug with RadioGroup ?

I tried to migrate this at one point, but IIRC my change has revealed that there was a bug somewhere because the bahavior changed somehow, not sure what was the issue at that time, did you manage to figure out what is the problem ?

@ValentinVignal
Copy link
Copy Markdown
Contributor Author

@AbdeMohlbi no I haven't, actually, I am not sure if the behavior is supposed to changed or not? That's why I opened the PR, to kickstart the discussion.

@victorsanni victorsanni self-requested a review March 23, 2026 17:33
victorsanni
victorsanni previously approved these changes Mar 24, 2026
Comment thread examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart
@victorsanni victorsanni added the CICD Run CI/CD label Mar 24, 2026
@loic-sharma
Copy link
Copy Markdown
Member

FYI it looks like it's failing a test:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: <true>
  Actual: <false>

When the exception was thrown, this was the stack:
#4      main.<anonymous closure> (file:///Volumes/Work/s/w/ir/x/w/flutter/examples/api/test/widgets/focus_manager/focus_node.unfocus.0_test.dart:75:7)
<asynchronous suspension>
#5      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:192:15)
<asynchronous suspension>
#6      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1954:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

This was caught by the test expectation on the following line:
  file:///Volumes/Work/s/w/ir/x/w/flutter/examples/api/test/widgets/focus_manager/focus_node.unfocus.0_test.dart line 75
The test description was:
  Unfocusing with UnfocusDisposition.previouslyFocusedChild gives the focus the previously focused
  child
════════════════════════════════════════════════════════════════════════════════════════════════════
02:45 +860 -1: /Volumes/Work/s/w/ir/x/w/flutter/examples/api/test/widgets/focus_manager/focus_node.unfocus.0_test.dart: Unfocusing with UnfocusDisposition.previouslyFocusedChild gives the focus the previously focused child [E]
  Test failed. See exception logs above.
  The test description was: Unfocusing with UnfocusDisposition.previouslyFocusedChild gives the focus the previously focused child

@ValentinVignal
Copy link
Copy Markdown
Contributor Author

@victorsanni @loic-sharma, thanks for reviewing/commenting.

What do you think of my comment here #183979 (comment)?

@loic-sharma
Copy link
Copy Markdown
Member

loic-sharma commented Mar 26, 2026

@ValentinVignal Oh sorry, I missed that comment! Unfortunately, I don't know the answer. I didn't migrate this test to RadioGroup since I didn't have the time to investigate. It's not clear to me why RadioGroup affects that test. It seems like this might be a bug in RadioGroup, but I'm not sure.

@justinmc
Copy link
Copy Markdown
Contributor

It looks like this PR needs more investigation but @ValentinVignal we'd love to get it landed if you have the time to figure out what's going on in #183979 (comment)!

@justinmc justinmc marked this pull request as draft April 7, 2026 22:40
@justinmc
Copy link
Copy Markdown
Contributor

justinmc commented Apr 7, 2026

Converted to draft to get it out of the review queue for now.

@flutter-dashboard
Copy link
Copy Markdown

This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@ValentinVignal ValentinVignal force-pushed the example/api/migrate-focus-node-unfocus-to-use-radio-group branch from dd2e7ac to 5d234bc Compare May 1, 2026 07:48
@github-actions github-actions Bot removed the CICD Run CI/CD label May 1, 2026
@ValentinVignal
Copy link
Copy Markdown
Contributor Author

I did some digging, and it looks like this is a desired behavior:

child: FocusTraversalGroup(
policy: _SkipUnselectedRadioPolicy<T>(_radios, widget.groupValue),
child: _RadioGroupStateScope<T>(
state: this,
groupValue: widget.groupValue,
child: widget.child,
),
),
),

There is an explicit focus policy _SkipUnselectedRadioPolicy in RadioGroup to prevent focusing on the unselected radios.

/// A traversal policy that is the same as [ReadingOrderTraversalPolicy] except
/// it skips nodes of unselected radio button if there is one selected radio
/// button.
///
/// If none of the radio is selected, this defaults to
/// [ReadingOrderTraversalPolicy] for all nodes.
///
/// This policy is to ensure when tabbing into a radio group, it will only focus
/// the current selected radio button and prevent focus from reaching unselected
/// ones.
class _SkipUnselectedRadioPolicy<T> extends ReadingOrderTraversalPolicy {

As a user, it kind of surprises me because it blocks me from changing the selected radio using tab + space/enter.

But maybe there is a reason behind it. Do you have some context @chunhtai ?

@ValentinVignal
Copy link
Copy Markdown
Contributor Author

ValentinVignal commented May 1, 2026

Re-opening the PR for visibility

@ValentinVignal ValentinVignal marked this pull request as ready for review May 1, 2026 08:25
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 1, 2026
Copy link
Copy Markdown
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 migrates the UnfocusExample widget to use RadioGroup for managing UnfocusDisposition radio buttons, removing deprecated code and manual state handling for individual radio buttons. The associated test was updated to reflect changes in focus traversal by reducing the number of tab key events required to reach the 'UNFOCUS' button. I have no feedback to provide.

@chunhtai chunhtai self-requested a review May 1, 2026 21:09
@chunhtai
Copy link
Copy Markdown
Contributor

chunhtai commented May 1, 2026

As a user, it kind of surprises me because it blocks me from changing the selected radio using tab + space/enter.

But maybe there is a reason behind it. Do you have some context @chunhtai ?

This is following the APG, which is also a requirement for WCAG and other public standard https://www.w3.org/WAI/ARIA/apg/patterns/radio/

to change focus, one should use arrow key instead. Though this only applies to alphabetic keyboard. We have not yet implement the correct focus traversal when using directional keyboard such as tv control or gamepad.

chunhtai
chunhtai previously approved these changes May 1, 2026
Copy link
Copy Markdown
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

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

LGTM

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 5, 2026
@victorsanni victorsanni added CICD Run CI/CD and removed CICD Run CI/CD labels May 5, 2026
@fluttergithubbot
Copy link
Copy Markdown
Contributor

An existing Git SHA, a739882bfa973d12c23c4e976d9e40a7b3602b74, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

@victorsanni victorsanni added CICD Run CI/CD and removed CICD Run CI/CD labels May 5, 2026
@fluttergithubbot
Copy link
Copy Markdown
Contributor

An existing Git SHA, a739882bfa973d12c23c4e976d9e40a7b3602b74, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

@github-actions github-actions Bot removed the CICD Run CI/CD label May 5, 2026
@AbdeMohlbi AbdeMohlbi added the CICD Run CI/CD label May 6, 2026
@ValentinVignal ValentinVignal added the autosubmit Merge PR when tree becomes green via auto submit App label May 12, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue May 12, 2026
Merged via the queue into flutter:master with commit 48a522d May 12, 2026
62 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label May 12, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request May 14, 2026
Roll Flutter from 707dbc0420a3 to 23f6f5853f50 (149 revisions)

flutter/flutter@707dbc0...23f6f58

2026-05-12 737941+loic-sharma@users.noreply.github.com Add 'cp: review' label to the manual cherrypick process (flutter/flutter#186158)
2026-05-12 engine-flutter-autoroll@skia.org Roll Packages from 19ec8b8 to 93cbed6 (3 revisions) (flutter/flutter#186401)
2026-05-12 30870216+gaaclarke@users.noreply.github.com Removes SDF option for macOS (always enabled) (flutter/flutter#186265)
2026-05-12 nico.reiab@gmail.com docs: fix typos in flutter_tools comments (flutter/flutter#186321)
2026-05-12 15619084+vashworth@users.noreply.github.com Pass XcodeBasedProject instead of String to functions in XcodeProjectInterpreter (flutter/flutter#186378)
2026-05-12 jason-simmons@users.noreply.github.com Update iOS scenario app test goldens to match changes from flutter/flutter#182662 (flutter/flutter#186390)
2026-05-12 engine-flutter-autoroll@skia.org Roll Skia from ad0aff15b9fa to 77a21bc723dc (2 revisions) (flutter/flutter#186396)
2026-05-12 32538273+ValentinVignal@users.noreply.github.com Migrate focus_node.unfocus.0.dart to use `RadioGroup` (flutter/flutter#183979)
2026-05-12 engine-flutter-autoroll@skia.org Roll Skia from 91d3c1e730af to ad0aff15b9fa (7 revisions) (flutter/flutter#186391)
2026-05-12 bdero@google.com [Flutter GPU] Allow customizing the vertex layout on a RenderPipeline (flutter/flutter#186310)
2026-05-12 97480502+b-luk@users.noreply.github.com Fix `EmbedderTest.CanRenderTextWithImpellerMetal` test breakage (flutter/flutter#186262)
2026-05-12 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from rFhU-YPqdCRCtCz7b... to z7ICmPtn4hspu02zk... (flutter/flutter#186384)
2026-05-12 bdero@google.com [Impeller] GLES: lazily allocate texture mip levels on first per-level write (flutter/flutter#186302)
2026-05-12 bdero@google.com [Android] Propagate --enable-flutter-gpu Intent extra to engine args (flutter/flutter#186298)
2026-05-11 47866232+chunhtai@users.noreply.github.com [ci] update no-response workflow to also look for old label name in e… (flutter/flutter#186373)
2026-05-11 bdero@google.com [ImpellerC] Write a depfile when --shader-bundle is in use (flutter/flutter#186341)
2026-05-11 nico.reiab@gmail.com docs: fix doubled-word typos in comments (flutter/flutter#186320)
2026-05-11 engine-flutter-autoroll@skia.org Roll Skia from 32281401997e to 91d3c1e730af (4 revisions) (flutter/flutter#186368)
2026-05-11 15619084+vashworth@users.noreply.github.com Show SwiftPM warnings right before iOS/macOS build (flutter/flutter#185984)
2026-05-11 15619084+vashworth@users.noreply.github.com Convert rebuilding-flutter-tool script to dart (flutter/flutter#185089)
2026-05-11 15619084+vashworth@users.noreply.github.com Use Xcode's LLDB (flutter/flutter#186273)
2026-05-11 mr-peipei@web.de Remove `currentMainUri` from `generateMainDartWithPluginRegistrant` (flutter/flutter#185907)
2026-05-11 engine-flutter-autoroll@skia.org Roll Skia from 2514f6b5f92b to 32281401997e (1 revision) (flutter/flutter#186349)
2026-05-11 engine-flutter-autoroll@skia.org Roll Packages from 92552b1 to 19ec8b8 (4 revisions) (flutter/flutter#186350)
2026-05-11 1063596+reidbaker@users.noreply.github.com Check for absolute paths in skills.  (flutter/flutter#185632)
2026-05-11 engine-flutter-autoroll@skia.org Roll Skia from 9fb7d2814642 to 2514f6b5f92b (1 revision) (flutter/flutter#186347)
2026-05-11 engine-flutter-autoroll@skia.org Roll Skia from 8cafb209e836 to 9fb7d2814642 (4 revisions) (flutter/flutter#186335)
2026-05-10 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from sOBiPJb0xznDBZlf5... to rFhU-YPqdCRCtCz7b... (flutter/flutter#186328)
2026-05-10 engine-flutter-autoroll@skia.org Roll Skia from 05a03f99c74e to 8cafb209e836 (1 revision) (flutter/flutter#186315)
2026-05-10 bdero@google.com [Impeller] Vulkan: don't drop user-supplied viewport X, Y, and depth range (flutter/flutter#185886)
2026-05-09 mbrase@google.com Update Fuchsia tests to subpackage their child components (flutter/flutter#186259)
2026-05-09 victorsanniay@gmail.com Fix SelectableText crash with inline lambda contextMenuBuilder (flutter/flutter#184990)
2026-05-09 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 5_TnhTsHSqtCx37o6... to sOBiPJb0xznDBZlf5... (flutter/flutter#186289)
2026-05-09 engine-flutter-autoroll@skia.org Roll Skia from dc78d4bd2efb to 05a03f99c74e (2 revisions) (flutter/flutter#186283)
2026-05-09 22373191+Hari-07@users.noreply.github.com Improve non rect platform view rendering  (flutter/flutter#182662)
2026-05-08 engine-flutter-autoroll@skia.org Roll Skia from 31521f8508c7 to dc78d4bd2efb (1 revision) (flutter/flutter#186278)
2026-05-08 30870216+gaaclarke@users.noreply.github.com Moves wide_gamut_macos to arm64 (flutter/flutter#186214)
2026-05-08 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[iOS] Migrate VSyncClient to a pure Obj-C implementation (#186166)" (flutter/flutter#186266)
2026-05-08 engine-flutter-autoroll@skia.org Roll Skia from a00db8749edb to 31521f8508c7 (2 revisions) (flutter/flutter#186264)
2026-05-08 97480502+b-luk@users.noreply.github.com Optimize compatible `DrawDiffRoundRect` calls to use `DrawRoundRect` (flutter/flutter#186203)
2026-05-08 bdero@google.com [triage] Add Flutter GPU as a triage team (flutter/flutter#186263)
2026-05-08 dmgr@google.com doc: Unified Check-Run User manual (flutter/flutter#186210)
2026-05-08 engine-flutter-autoroll@skia.org Roll Skia from 5f7adf4403d6 to a00db8749edb (1 revision) (flutter/flutter#186257)
2026-05-08 engine-flutter-autoroll@skia.org Roll Packages from 0411f1d to 92552b1 (1 revision) (flutter/flutter#186256)
2026-05-08 34871572+gmackall@users.noreply.github.com Add logging to figure out jvm crashes for `hot_mode_tests` (flutter/flutter#186107)
2026-05-08 engine-flutter-autoroll@skia.org Roll Skia from 926c09741ce2 to 5f7adf4403d6 (3 revisions) (flutter/flutter#186242)
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: focus Focus traversal, gaining or losing focus framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate samples' Radio to RadioGroup

7 participants