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
This commit is contained in:
parent
6205c110d6
commit
1daa0be4f9
@ -1659,6 +1659,7 @@ class _RenderScrollSemantics extends RenderProxyBox {
|
|||||||
@override
|
@override
|
||||||
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable<SemanticsNode> children) {
|
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable<SemanticsNode> children) {
|
||||||
if (children.isEmpty || !children.first.isTagged(RenderViewport.useTwoPaneSemantics)) {
|
if (children.isEmpty || !children.first.isTagged(RenderViewport.useTwoPaneSemantics)) {
|
||||||
|
_innerNode = null;
|
||||||
super.assembleSemanticsNode(node, config, children);
|
super.assembleSemanticsNode(node, config, children);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ import 'package:flutter/scheduler.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'semantics_tester.dart';
|
||||||
|
|
||||||
Future<void> pumpTest(
|
Future<void> pumpTest(
|
||||||
WidgetTester tester,
|
WidgetTester tester,
|
||||||
TargetPlatform? platform, {
|
TargetPlatform? platform, {
|
||||||
@ -1643,6 +1645,51 @@ void main() {
|
|||||||
await tester.pump(const Duration(milliseconds: 4800));
|
await tester.pump(const Duration(milliseconds: 4800));
|
||||||
expect(getScrollOffset(tester), closeTo(333.2944, 0.0001));
|
expect(getScrollOffset(tester), closeTo(333.2944, 0.0001));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Swapping viewports in a scrollable does not crash', (WidgetTester tester) async {
|
||||||
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
|
final GlobalKey key = GlobalKey();
|
||||||
|
final GlobalKey key1 = GlobalKey();
|
||||||
|
Widget buildScrollable(bool withViewPort) {
|
||||||
|
return Scrollable(
|
||||||
|
key: key,
|
||||||
|
viewportBuilder: (BuildContext context, ViewportOffset position) {
|
||||||
|
if (withViewPort) {
|
||||||
|
return Viewport(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(child: Semantics(key: key1, container: true, child: const Text('text1')))
|
||||||
|
],
|
||||||
|
offset: ViewportOffset.zero(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Semantics(key: key1, container: true, child: const Text('text1'));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// This should cache the inner node in Scrollable with the children text1.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: buildScrollable(true),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(semantics, includesNodeWith(tags: <SemanticsTag>{RenderViewport.useTwoPaneSemantics}));
|
||||||
|
// This does not use two panel, this should clear cached inner node.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: buildScrollable(false),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(semantics, isNot(includesNodeWith(tags: <SemanticsTag>{RenderViewport.useTwoPaneSemantics})));
|
||||||
|
// If the inner node was cleared in the previous step, this should not crash.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: buildScrollable(true),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(semantics, includesNodeWith(tags: <SemanticsTag>{RenderViewport.useTwoPaneSemantics}));
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
semantics.dispose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
|
@ -487,6 +487,7 @@ class SemanticsTester {
|
|||||||
TextDirection? textDirection,
|
TextDirection? textDirection,
|
||||||
List<SemanticsAction>? actions,
|
List<SemanticsAction>? actions,
|
||||||
List<SemanticsFlag>? flags,
|
List<SemanticsFlag>? flags,
|
||||||
|
Set<SemanticsTag>? tags,
|
||||||
double? scrollPosition,
|
double? scrollPosition,
|
||||||
double? scrollExtentMax,
|
double? scrollExtentMax,
|
||||||
double? scrollExtentMin,
|
double? scrollExtentMin,
|
||||||
@ -536,6 +537,12 @@ class SemanticsTester {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (tags != null) {
|
||||||
|
final Set<SemanticsTag>? actualTags = node.getSemanticsData().tags;
|
||||||
|
if (!setEquals<SemanticsTag>(actualTags, tags)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (scrollPosition != null && !nearEqual(node.scrollPosition, scrollPosition, 0.1)) {
|
if (scrollPosition != null && !nearEqual(node.scrollPosition, scrollPosition, 0.1)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -796,6 +803,7 @@ class _IncludesNodeWith extends Matcher {
|
|||||||
this.textDirection,
|
this.textDirection,
|
||||||
this.actions,
|
this.actions,
|
||||||
this.flags,
|
this.flags,
|
||||||
|
this.tags,
|
||||||
this.scrollPosition,
|
this.scrollPosition,
|
||||||
this.scrollExtentMax,
|
this.scrollExtentMax,
|
||||||
this.scrollExtentMin,
|
this.scrollExtentMin,
|
||||||
@ -806,6 +814,7 @@ class _IncludesNodeWith extends Matcher {
|
|||||||
value != null ||
|
value != null ||
|
||||||
actions != null ||
|
actions != null ||
|
||||||
flags != null ||
|
flags != null ||
|
||||||
|
tags != null ||
|
||||||
scrollPosition != null ||
|
scrollPosition != null ||
|
||||||
scrollExtentMax != null ||
|
scrollExtentMax != null ||
|
||||||
scrollExtentMin != null ||
|
scrollExtentMin != null ||
|
||||||
@ -821,6 +830,7 @@ class _IncludesNodeWith extends Matcher {
|
|||||||
final TextDirection? textDirection;
|
final TextDirection? textDirection;
|
||||||
final List<SemanticsAction>? actions;
|
final List<SemanticsAction>? actions;
|
||||||
final List<SemanticsFlag>? flags;
|
final List<SemanticsFlag>? flags;
|
||||||
|
final Set<SemanticsTag>? tags;
|
||||||
final double? scrollPosition;
|
final double? scrollPosition;
|
||||||
final double? scrollExtentMax;
|
final double? scrollExtentMax;
|
||||||
final double? scrollExtentMin;
|
final double? scrollExtentMin;
|
||||||
@ -839,6 +849,7 @@ class _IncludesNodeWith extends Matcher {
|
|||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
actions: actions,
|
actions: actions,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
tags: tags,
|
||||||
scrollPosition: scrollPosition,
|
scrollPosition: scrollPosition,
|
||||||
scrollExtentMax: scrollExtentMax,
|
scrollExtentMax: scrollExtentMax,
|
||||||
scrollExtentMin: scrollExtentMin,
|
scrollExtentMin: scrollExtentMin,
|
||||||
@ -865,6 +876,7 @@ class _IncludesNodeWith extends Matcher {
|
|||||||
if (textDirection != null) ' (${textDirection!.name})',
|
if (textDirection != null) ' (${textDirection!.name})',
|
||||||
if (actions != null) 'actions "${actions!.join(', ')}"',
|
if (actions != null) 'actions "${actions!.join(', ')}"',
|
||||||
if (flags != null) 'flags "${flags!.join(', ')}"',
|
if (flags != null) 'flags "${flags!.join(', ')}"',
|
||||||
|
if (tags != null) 'tags "${tags!.join(', ')}"',
|
||||||
if (scrollPosition != null) 'scrollPosition "$scrollPosition"',
|
if (scrollPosition != null) 'scrollPosition "$scrollPosition"',
|
||||||
if (scrollExtentMax != null) 'scrollExtentMax "$scrollExtentMax"',
|
if (scrollExtentMax != null) 'scrollExtentMax "$scrollExtentMax"',
|
||||||
if (scrollExtentMin != null) 'scrollExtentMin "$scrollExtentMin"',
|
if (scrollExtentMin != null) 'scrollExtentMin "$scrollExtentMin"',
|
||||||
@ -889,6 +901,7 @@ Matcher includesNodeWith({
|
|||||||
TextDirection? textDirection,
|
TextDirection? textDirection,
|
||||||
List<SemanticsAction>? actions,
|
List<SemanticsAction>? actions,
|
||||||
List<SemanticsFlag>? flags,
|
List<SemanticsFlag>? flags,
|
||||||
|
Set<SemanticsTag>? tags,
|
||||||
double? scrollPosition,
|
double? scrollPosition,
|
||||||
double? scrollExtentMax,
|
double? scrollExtentMax,
|
||||||
double? scrollExtentMin,
|
double? scrollExtentMin,
|
||||||
@ -905,6 +918,7 @@ Matcher includesNodeWith({
|
|||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
actions: actions,
|
actions: actions,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
tags: tags,
|
||||||
scrollPosition: scrollPosition,
|
scrollPosition: scrollPosition,
|
||||||
scrollExtentMax: scrollExtentMax,
|
scrollExtentMax: scrollExtentMax,
|
||||||
scrollExtentMin: scrollExtentMin,
|
scrollExtentMin: scrollExtentMin,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user