Set stable color for semantics debugger (#157884)
fixes https://github.com/flutter/flutter/issues/156242 ## 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]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] 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/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#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/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
9cffcefa15
commit
fe087fff95
@ -2092,8 +2092,7 @@ class SemanticsNode with DiagnosticableTreeMixin {
|
||||
/// Visits the immediate children of this node.
|
||||
///
|
||||
/// This function calls visitor for each immediate child until visitor returns
|
||||
/// false. Returns true if all the visitor calls returned true, otherwise
|
||||
/// returns false.
|
||||
/// false.
|
||||
void visitChildren(SemanticsNodeVisitor visitor) {
|
||||
if (_children != null) {
|
||||
for (final SemanticsNode child in _children!) {
|
||||
|
@ -202,7 +202,7 @@ class _SemanticsDebuggerPainter extends CustomPainter {
|
||||
canvas.save();
|
||||
canvas.scale(1.0 / devicePixelRatio, 1.0 / devicePixelRatio);
|
||||
if (rootNode != null) {
|
||||
_paint(canvas, rootNode, _findDepth(rootNode));
|
||||
_paint(canvas, rootNode, _findDepth(rootNode), 0, 0);
|
||||
}
|
||||
if (pointerPosition != null) {
|
||||
final Paint paint = Paint();
|
||||
@ -332,14 +332,14 @@ class _SemanticsDebuggerPainter extends CustomPainter {
|
||||
return childrenDepth + 1;
|
||||
}
|
||||
|
||||
void _paint(Canvas canvas, SemanticsNode node, int rank) {
|
||||
void _paint(Canvas canvas, SemanticsNode node, int rank, int indexInParent, int level) {
|
||||
canvas.save();
|
||||
if (node.transform != null) {
|
||||
canvas.transform(node.transform!.storage);
|
||||
}
|
||||
final Rect rect = node.rect;
|
||||
if (!rect.isEmpty) {
|
||||
final Color lineColor = Color(0xFF000000 + math.Random(node.id).nextInt(0xFFFFFF));
|
||||
final Color lineColor = _colorForNode(indexInParent, level);
|
||||
final Rect innerRect = rect.deflate(rank * 1.0);
|
||||
if (innerRect.isEmpty) {
|
||||
final Paint fill = Paint()
|
||||
@ -361,13 +361,31 @@ class _SemanticsDebuggerPainter extends CustomPainter {
|
||||
}
|
||||
if (!node.mergeAllDescendantsIntoThisNode) {
|
||||
final int childRank = rank - 1;
|
||||
final int childLevel = level + 1;
|
||||
int childIndex = 0;
|
||||
node.visitChildren((SemanticsNode child) {
|
||||
_paint(canvas, child, childRank);
|
||||
_paint(canvas, child, childRank, childIndex, childLevel);
|
||||
childIndex += 1;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
static Color _colorForNode(int index, int level) {
|
||||
return HSLColor.fromAHSL(
|
||||
1.0,
|
||||
// Use custom hash to ensure stable value regardless of Dart changes
|
||||
360.0 * math.Random(_getColorSeed(index, level)).nextDouble(),
|
||||
1.0,
|
||||
0.7,
|
||||
).toColor();
|
||||
}
|
||||
|
||||
static int _getColorSeed(int level, int index) {
|
||||
// Should be no collision as long as children number < 10000.
|
||||
return level * 10000 + index;
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget ignores pointer event but still keeps semantics actions.
|
||||
|
@ -61,6 +61,26 @@ void main() {
|
||||
expect(true, isTrue); // expect that we reach here without crashing
|
||||
});
|
||||
|
||||
testWidgets('SemanticsDebugger draw persistent color based on structure', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SemanticsDebugger(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Semantics(
|
||||
container: true,
|
||||
child: Semantics(container: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(SemanticsDebugger), paints..rect()..rect(color: const Color(0xFFF866FF)));
|
||||
});
|
||||
|
||||
testWidgets('SemanticsDebugger reparents subtree', (WidgetTester tester) async {
|
||||
final GlobalKey key = GlobalKey();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user