Refactor route focus node creation (#147390)
## Description This fixes an issue in the creation of the `FocusScope` in a route: the route should be creating the `FocusScope` widget it has with `withExternalFocusNode`, since it is modifying the node attributes in a builder. Also modified some `AnimatedBuilder`s to be `ListenableBuilder`s, since they're not using animations (no functionality change there, since the implementation of the two is identical). ## Related Issues - #147256 - Fixes #146844 ## Tests - Updated example test.
This commit is contained in:
parent
973d3a009b
commit
d274a2126f
@ -10,7 +10,7 @@ void main() {
|
|||||||
testWidgets('Tapping FAB increments counter', (WidgetTester tester) async {
|
testWidgets('Tapping FAB increments counter', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(const example.ListenableBuilderExample());
|
await tester.pumpWidget(const example.ListenableBuilderExample());
|
||||||
|
|
||||||
String getCount() => (tester.widget(find.descendant(of: find.byType(ListenableBuilder), matching: find.byType(Text))) as Text).data!;
|
String getCount() => (tester.widget(find.descendant(of: find.byType(ListenableBuilder).last, matching: find.byType(Text))) as Text).data!;
|
||||||
|
|
||||||
expect(find.text('Current counter value:'), findsOneWidget);
|
expect(find.text('Current counter value:'), findsOneWidget);
|
||||||
expect(find.text('0'), findsOneWidget);
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
@ -1022,6 +1022,8 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// Only top most route can participate in focus traversal.
|
||||||
|
focusScopeNode.skipTraversal = !widget.route.isCurrent;
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: widget.route.restorationScopeId,
|
animation: widget.route.restorationScopeId,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
@ -1048,24 +1050,22 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
|
|||||||
},
|
},
|
||||||
child: PrimaryScrollController(
|
child: PrimaryScrollController(
|
||||||
controller: primaryScrollController,
|
controller: primaryScrollController,
|
||||||
child: FocusScope(
|
child: FocusScope.withExternalFocusNode(
|
||||||
node: focusScopeNode, // immutable
|
focusScopeNode: focusScopeNode, // immutable
|
||||||
// Only top most route can participate in focus traversal.
|
|
||||||
skipTraversal: !widget.route.isCurrent,
|
|
||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
child: AnimatedBuilder(
|
child: ListenableBuilder(
|
||||||
animation: _listenable, // immutable
|
listenable: _listenable, // immutable
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
return widget.route.buildTransitions(
|
return widget.route.buildTransitions(
|
||||||
context,
|
context,
|
||||||
widget.route.animation!,
|
widget.route.animation!,
|
||||||
widget.route.secondaryAnimation!,
|
widget.route.secondaryAnimation!,
|
||||||
// This additional AnimatedBuilder is include because if the
|
// This additional ListenableBuilder is include because if the
|
||||||
// value of the userGestureInProgressNotifier changes, it's
|
// value of the userGestureInProgressNotifier changes, it's
|
||||||
// only necessary to rebuild the IgnorePointer widget and set
|
// only necessary to rebuild the IgnorePointer widget and set
|
||||||
// the focus node's ability to focus.
|
// the focus node's ability to focus.
|
||||||
AnimatedBuilder(
|
ListenableBuilder(
|
||||||
animation: widget.route.navigator?.userGestureInProgressNotifier ?? ValueNotifier<bool>(false),
|
listenable: widget.route.navigator?.userGestureInProgressNotifier ?? ValueNotifier<bool>(false),
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
final bool ignoreEvents = _shouldIgnoreFocusRequest;
|
final bool ignoreEvents = _shouldIgnoreFocusRequest;
|
||||||
focusScopeNode.canRequestFocus = !ignoreEvents;
|
focusScopeNode.canRequestFocus = !ignoreEvents;
|
||||||
|
@ -1736,7 +1736,7 @@ void main() {
|
|||||||
semantics.dispose();
|
semantics.dispose();
|
||||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.iOS}));
|
}, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.iOS}));
|
||||||
|
|
||||||
testWidgets('focus traverse correct when pop multiple page simultaneously', (WidgetTester tester) async {
|
testWidgets('focus traversal is correct when popping multiple pages simultaneously', (WidgetTester tester) async {
|
||||||
// Regression test: https://github.com/flutter/flutter/issues/48903
|
// Regression test: https://github.com/flutter/flutter/issues/48903
|
||||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user