Skip to content

Commit f2050e8

Browse files
authored
Fixes focus traversal crash if the current node can't request focus (flutter#134954)
fixes flutter#134854 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] 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/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#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/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent 43407cf commit f2050e8

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

packages/flutter/lib/src/widgets/focus_traversal.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,9 @@ abstract class FocusTraversalPolicy with Diagnosticable {
433433
// finds.
434434
assert((){
435435
final Set<FocusNode> difference = sortedDescendants.toSet().difference(scope.traversalDescendants.toSet());
436-
if (currentNode.skipTraversal) {
436+
if (currentNode.skipTraversal || !currentNode.canRequestFocus) {
437+
// The scope.traversalDescendants will not contain currentNode if it
438+
// skips traversal or not focusable.
437439
assert(
438440
difference.length == 1 && difference.contains(currentNode),
439441
'Sorted descendants contains different nodes than FocusScopeNode.traversalDescendants would. '

packages/flutter/test/widgets/focus_traversal_test.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,41 @@ void main() {
596596
expect(scope.hasFocus, isTrue);
597597
});
598598

599+
testWidgetsWithLeakTracking('Requesting nextFocus on node focuses its descendant', (WidgetTester tester) async {
600+
for (final bool canRequestFocus in <bool>{true, false}) {
601+
final FocusNode node1 = FocusNode();
602+
final FocusNode node2 = FocusNode();
603+
addTearDown(() {
604+
node1.dispose();
605+
node2.dispose();
606+
});
607+
await tester.pumpWidget(
608+
Directionality(
609+
textDirection: TextDirection.ltr,
610+
child: FocusTraversalGroup(
611+
policy: ReadingOrderTraversalPolicy(),
612+
child: FocusScope(
613+
child: Focus(
614+
focusNode: node1,
615+
canRequestFocus: canRequestFocus,
616+
child: Focus(
617+
focusNode: node2,
618+
child: Container(),
619+
),
620+
),
621+
),
622+
),
623+
),
624+
);
625+
626+
final bool didFindNode = node1.nextFocus();
627+
await tester.pump();
628+
expect(didFindNode, isTrue);
629+
expect(node1.hasPrimaryFocus, isFalse);
630+
expect(node2.hasPrimaryFocus, isTrue);
631+
}
632+
});
633+
599634
testWidgetsWithLeakTracking('Move reading focus to previous node.', (WidgetTester tester) async {
600635
final GlobalKey key1 = GlobalKey(debugLabel: '1');
601636
final GlobalKey key2 = GlobalKey(debugLabel: '2');

0 commit comments

Comments
 (0)