Skip to content

Commit 1daa0be

Browse files
authored
Fix scrollable to clear inner semantics node if it does not use two p… (#120996)
* Fix scrollable to clear inner semantics node if it does not use two panel * g * add more check
1 parent 6205c11 commit 1daa0be

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,6 +1659,7 @@ class _RenderScrollSemantics extends RenderProxyBox {
16591659
@override
16601660
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable<SemanticsNode> children) {
16611661
if (children.isEmpty || !children.first.isTagged(RenderViewport.useTwoPaneSemantics)) {
1662+
_innerNode = null;
16621663
super.assembleSemanticsNode(node, config, children);
16631664
return;
16641665
}

packages/flutter/test/widgets/scrollable_test.dart

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import 'package:flutter/scheduler.dart';
1111
import 'package:flutter/services.dart';
1212
import 'package:flutter_test/flutter_test.dart';
1313

14+
import 'semantics_tester.dart';
15+
1416
Future<void> pumpTest(
1517
WidgetTester tester,
1618
TargetPlatform? platform, {
@@ -1643,6 +1645,51 @@ void main() {
16431645
await tester.pump(const Duration(milliseconds: 4800));
16441646
expect(getScrollOffset(tester), closeTo(333.2944, 0.0001));
16451647
});
1648+
1649+
testWidgets('Swapping viewports in a scrollable does not crash', (WidgetTester tester) async {
1650+
final SemanticsTester semantics = SemanticsTester(tester);
1651+
final GlobalKey key = GlobalKey();
1652+
final GlobalKey key1 = GlobalKey();
1653+
Widget buildScrollable(bool withViewPort) {
1654+
return Scrollable(
1655+
key: key,
1656+
viewportBuilder: (BuildContext context, ViewportOffset position) {
1657+
if (withViewPort) {
1658+
return Viewport(
1659+
slivers: <Widget>[
1660+
SliverToBoxAdapter(child: Semantics(key: key1, container: true, child: const Text('text1')))
1661+
],
1662+
offset: ViewportOffset.zero(),
1663+
);
1664+
}
1665+
return Semantics(key: key1, container: true, child: const Text('text1'));
1666+
},
1667+
);
1668+
}
1669+
// This should cache the inner node in Scrollable with the children text1.
1670+
await tester.pumpWidget(
1671+
MaterialApp(
1672+
home: buildScrollable(true),
1673+
),
1674+
);
1675+
expect(semantics, includesNodeWith(tags: <SemanticsTag>{RenderViewport.useTwoPaneSemantics}));
1676+
// This does not use two panel, this should clear cached inner node.
1677+
await tester.pumpWidget(
1678+
MaterialApp(
1679+
home: buildScrollable(false),
1680+
),
1681+
);
1682+
expect(semantics, isNot(includesNodeWith(tags: <SemanticsTag>{RenderViewport.useTwoPaneSemantics})));
1683+
// If the inner node was cleared in the previous step, this should not crash.
1684+
await tester.pumpWidget(
1685+
MaterialApp(
1686+
home: buildScrollable(true),
1687+
),
1688+
);
1689+
expect(semantics, includesNodeWith(tags: <SemanticsTag>{RenderViewport.useTwoPaneSemantics}));
1690+
expect(tester.takeException(), isNull);
1691+
semantics.dispose();
1692+
});
16461693
}
16471694

16481695
// ignore: must_be_immutable

packages/flutter/test/widgets/semantics_tester.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ class SemanticsTester {
487487
TextDirection? textDirection,
488488
List<SemanticsAction>? actions,
489489
List<SemanticsFlag>? flags,
490+
Set<SemanticsTag>? tags,
490491
double? scrollPosition,
491492
double? scrollExtentMax,
492493
double? scrollExtentMin,
@@ -536,6 +537,12 @@ class SemanticsTester {
536537
return false;
537538
}
538539
}
540+
if (tags != null) {
541+
final Set<SemanticsTag>? actualTags = node.getSemanticsData().tags;
542+
if (!setEquals<SemanticsTag>(actualTags, tags)) {
543+
return false;
544+
}
545+
}
539546
if (scrollPosition != null && !nearEqual(node.scrollPosition, scrollPosition, 0.1)) {
540547
return false;
541548
}
@@ -796,6 +803,7 @@ class _IncludesNodeWith extends Matcher {
796803
this.textDirection,
797804
this.actions,
798805
this.flags,
806+
this.tags,
799807
this.scrollPosition,
800808
this.scrollExtentMax,
801809
this.scrollExtentMin,
@@ -806,6 +814,7 @@ class _IncludesNodeWith extends Matcher {
806814
value != null ||
807815
actions != null ||
808816
flags != null ||
817+
tags != null ||
809818
scrollPosition != null ||
810819
scrollExtentMax != null ||
811820
scrollExtentMin != null ||
@@ -821,6 +830,7 @@ class _IncludesNodeWith extends Matcher {
821830
final TextDirection? textDirection;
822831
final List<SemanticsAction>? actions;
823832
final List<SemanticsFlag>? flags;
833+
final Set<SemanticsTag>? tags;
824834
final double? scrollPosition;
825835
final double? scrollExtentMax;
826836
final double? scrollExtentMin;
@@ -839,6 +849,7 @@ class _IncludesNodeWith extends Matcher {
839849
textDirection: textDirection,
840850
actions: actions,
841851
flags: flags,
852+
tags: tags,
842853
scrollPosition: scrollPosition,
843854
scrollExtentMax: scrollExtentMax,
844855
scrollExtentMin: scrollExtentMin,
@@ -865,6 +876,7 @@ class _IncludesNodeWith extends Matcher {
865876
if (textDirection != null) ' (${textDirection!.name})',
866877
if (actions != null) 'actions "${actions!.join(', ')}"',
867878
if (flags != null) 'flags "${flags!.join(', ')}"',
879+
if (tags != null) 'tags "${tags!.join(', ')}"',
868880
if (scrollPosition != null) 'scrollPosition "$scrollPosition"',
869881
if (scrollExtentMax != null) 'scrollExtentMax "$scrollExtentMax"',
870882
if (scrollExtentMin != null) 'scrollExtentMin "$scrollExtentMin"',
@@ -889,6 +901,7 @@ Matcher includesNodeWith({
889901
TextDirection? textDirection,
890902
List<SemanticsAction>? actions,
891903
List<SemanticsFlag>? flags,
904+
Set<SemanticsTag>? tags,
892905
double? scrollPosition,
893906
double? scrollExtentMax,
894907
double? scrollExtentMin,
@@ -905,6 +918,7 @@ Matcher includesNodeWith({
905918
textDirection: textDirection,
906919
actions: actions,
907920
flags: flags,
921+
tags: tags,
908922
scrollPosition: scrollPosition,
909923
scrollExtentMax: scrollExtentMax,
910924
scrollExtentMin: scrollExtentMin,

0 commit comments

Comments
 (0)