Skip to content

Clear cached directional focus history on a non-directional focus request #187957

Merged
auto-submit[bot] merged 13 commits into
flutter:masterfrom
elliette:focus-traversal-fix
Jul 22, 2026
Merged

Clear cached directional focus history on a non-directional focus request #187957
auto-submit[bot] merged 13 commits into
flutter:masterfrom
elliette:focus-traversal-fix

Conversation

@elliette

@elliette elliette commented Jun 12, 2026

Copy link
Copy Markdown
Member

Fixes #85941

When a user traverses focus nodes directionally (e.g. using up, down arrow keys), we maintain a history stack of visited nodes (called policyData). This allows us to avoid hysteresis when a user switches direction (i.e. switching from down to up) - meaning, the forward traversal path and the reversed traversal path should match.

However, before this change, we were not detecting when a focus request occurred due to some outside event (e.g. a direct focus request from a tap on the screen). That means when a user switched direction, we would include the node they had tapped on in the history stack, and unexpectedly visit it.

We now clear the stack (see method propagateFocusRequest) if a node is focused on outside of a directional navigation event.

Before:

before

With fix:

fixed

Pre-launch Checklist

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

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

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.

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 12, 2026
@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. f: focus Focus traversal, gaining or losing focus labels Jun 12, 2026

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

Copy link
Copy Markdown
Contributor

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 introduces a mechanism to invalidate cached focus traversal policy data when focus shifts outside of an active traversal action, such as during an explicit focus request. It tracks active directional traversals within FocusTraversalGroup and triggers scope invalidation accordingly, supported by a new regression test. The feedback suggests modifying the invalidation logic in _maybeInvalidatePolicyData to use a Set to track and prevent redundant invalidations of the same policy when walking up the focus tree.

Comment thread packages/flutter/lib/src/widgets/focus_manager.dart Outdated
Comment thread packages/flutter/lib/src/widgets/focus_manager.dart Outdated

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for taking a shot at this old and very visible issue.

By the way, what's your setup for creating the gifs with text on them??

Comment thread packages/flutter/test/widgets/focus_traversal_test.dart Outdated
Comment thread packages/flutter/test/widgets/focus_traversal_test.dart Outdated
Comment thread packages/flutter/test/widgets/focus_traversal_test.dart Outdated
Comment thread packages/flutter/test/widgets/focus_traversal_test.dart Outdated
Comment thread packages/flutter/lib/src/widgets/focus_traversal.dart Outdated
Comment thread packages/flutter/lib/src/widgets/focus_traversal.dart Outdated
Comment thread packages/flutter/lib/src/widgets/focus_manager.dart Outdated
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 22, 2026
@elliette
elliette force-pushed the focus-traversal-fix branch from 358e15c to 66aa9c6 Compare June 22, 2026 18:43
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 22, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 22, 2026
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 22, 2026
@elliette

Copy link
Copy Markdown
Member Author

Thanks for taking a shot at this old and very visible issue.

By the way, what's your setup for creating the gifs with text on them??

I use the Giphy Capture app which lets you add captions to a gif

@elliette
elliette requested review from chunhtai and justinmc June 22, 2026 19:44

@chunhtai chunhtai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

my latest comment #187957 (comment)

@elliette

Copy link
Copy Markdown
Member Author

my latest comment #187957 (comment)

Thanks! Have not had a chance to get back to this yet, will respond once I do!

@elliette
elliette force-pushed the focus-traversal-fix branch from 08a5d7a to 32a1b2b Compare July 13, 2026 23:37
@justinmc
justinmc requested a review from chunhtai July 14, 2026 22:29
chunhtai
chunhtai previously approved these changes Jul 15, 2026

@chunhtai chunhtai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, left a minor comment.

though this is slightly more fragile than the other approach for example we now relies on defaultTraversalRequestFocusCallback to call request focus on the node. but I can't think of a better way without introducing new API.

Comment thread packages/flutter/lib/src/widgets/focus_traversal.dart Outdated
justinmc
justinmc previously approved these changes Jul 20, 2026

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 👍

Comment thread packages/flutter/lib/src/widgets/focus_traversal.dart Outdated

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 👍

@elliette elliette added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 22, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Jul 22, 2026
Merged via the queue into flutter:master with commit 2a2a79d Jul 22, 2026
28 of 29 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 22, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Jul 22, 2026
flutter/flutter@1ac2e82...2a2a79d

2026-07-22 [email protected] Clear cached directional focus history on a non-directional focus request  (flutter/flutter#187957)
2026-07-22 [email protected] ci: Include root pubspec.yaml in pub cache key (flutter/flutter#189826)
2026-07-22 [email protected] Remove codecov badge from README (flutter/flutter#189728)
2026-07-22 [email protected] Clean android engine/embedding tests (flutter/flutter#189276)
2026-07-22 [email protected] Add barrierBuilder support to showDialog and showGeneralDialog (flutter/flutter#187992)
2026-07-22 [email protected] Fix Mockito dynamic agent loading warnings in Robolectric tests (flutter/flutter#189804)
2026-07-22 [email protected] [iOS] Remove dead RasterThreadMerger plumbing from platform views (flutter/flutter#189753)
2026-07-22 [email protected] Add OverlayPortal.overlayChildLayoutBuilder sample (flutter/flutter#188930)
2026-07-22 [email protected] Automate recurring tasks via workflows - localizations (flutter/flutter#189750)
2026-07-21 [email protected] [iOS] Remove dead parameters and no-op overrides (flutter/flutter#189754)
2026-07-21 [email protected] [iOS] Inject DisplayLinkManager into FlutterViewController (flutter/flutter#189764)
2026-07-21 [email protected] Support custom BoxBorder animation in BoxDecoration (flutter/flutter#186348)
2026-07-21 [email protected] Rename CpuArch.x86_64 to CpuArch.x64 (flutter/flutter#189478)
2026-07-21 [email protected] Roll Skia from 569534e9fa59 to 5e183e5aeac5 (3 revisions) (flutter/flutter#189795)
2026-07-21 [email protected] Roll Dart SDK from 3b2f5ad7718d to 1e65011ee004 (4 revisions) (flutter/flutter#189791)
2026-07-21 [email protected] Run delete-bot-branches.yaml on `pull_request_target` instead of `pull_request` so that we can access secrets. (flutter/flutter#189793)
2026-07-21 [email protected] Batch release directory correction (flutter/flutter#189738)
2026-07-21 [email protected] [flutter_test][Test cross imports] Move TestWidgetsApp to flutter_test (flutter/flutter#189435)
2026-07-21 [email protected] Fix null-deref/double-dispose in StretchingOverscrollIndicator (#189589) (flutter/flutter#189667)
2026-07-21 [email protected] Roll Packages from 611899b to 8260a1e (10 revisions) (flutter/flutter#189782)
2026-07-21 [email protected] [iOS] Inject DisplayLinkManager into FlutterMetalLayer (flutter/flutter#189752)
2026-07-21 [email protected] Derive the SkImage size used by ImageEncodingImpeller::ConvertDlImageToSkImage from the size of the underlying texture, not the size of the DlImage (flutter/flutter#189739)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD 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.

Focus traversal is unintuitive after requestFocus

3 participants