Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
6d303af9
Unverified
Commit
6d303af9
authored
Jul 23, 2020
by
David Martos
Committed by
GitHub
Jul 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use the correct Transform in the WidgetInspector overlay (#59566) (#60990)
parent
9da74f66
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
157 additions
and
5 deletions
+157
-5
widget_inspector.dart
packages/flutter/lib/src/widgets/widget_inspector.dart
+40
-5
widget_inspector_test.dart
packages/flutter/test/widgets/widget_inspector_test.dart
+117
-0
No files found.
packages/flutter/lib/src/widgets/widget_inspector.dart
View file @
6d303af9
...
...
@@ -2293,6 +2293,9 @@ class _WidgetInspectorState extends State<WidgetInspector>
@override
Widget
build
(
BuildContext
context
)
{
// Be careful changing this build method. The _InspectorOverlayLayer
// assumes the root RenderObject for the WidgetInspector will be
// a RenderStack with a _RenderInspectorOverlay as the last child.
return
Stack
(
children:
<
Widget
>[
GestureDetector
(
onTap:
_handleTap
,
...
...
@@ -2441,15 +2444,16 @@ class _RenderInspectorOverlay extends RenderBox {
context
.
addLayer
(
_InspectorOverlayLayer
(
overlayRect:
Rect
.
fromLTWH
(
offset
.
dx
,
offset
.
dy
,
size
.
width
,
size
.
height
),
selection:
selection
,
rootRenderObject:
parent
is
RenderObject
?
parent
as
RenderObject
:
null
,
));
}
}
@immutable
class
_TransformedRect
{
_TransformedRect
(
RenderObject
object
)
_TransformedRect
(
RenderObject
object
,
RenderObject
ancestor
)
:
rect
=
object
.
semanticBounds
,
transform
=
object
.
getTransformTo
(
null
);
transform
=
object
.
getTransformTo
(
ancestor
);
final
Rect
rect
;
final
Matrix4
transform
;
...
...
@@ -2517,6 +2521,7 @@ class _InspectorOverlayLayer extends Layer {
_InspectorOverlayLayer
({
@required
this
.
overlayRect
,
@required
this
.
selection
,
@required
this
.
rootRenderObject
,
})
:
assert
(
overlayRect
!=
null
),
assert
(
selection
!=
null
)
{
bool
inDebugMode
=
false
;
...
...
@@ -2543,6 +2548,10 @@ class _InspectorOverlayLayer extends Layer {
/// (as described at [Layer]).
final
Rect
overlayRect
;
/// Widget inspector root render object. The selection overlay will be painted
/// with transforms relative to this render object.
final
RenderObject
rootRenderObject
;
_InspectorOverlayRenderState
_lastState
;
/// Picture generated from _lastState.
...
...
@@ -2557,16 +2566,21 @@ class _InspectorOverlayLayer extends Layer {
return
;
final
RenderObject
selected
=
selection
.
current
;
if
(!
_isInInspectorRenderObjectTree
(
selected
))
return
;
final
List
<
_TransformedRect
>
candidates
=
<
_TransformedRect
>[];
for
(
final
RenderObject
candidate
in
selection
.
candidates
)
{
if
(
candidate
==
selected
||
!
candidate
.
attached
)
if
(
candidate
==
selected
||
!
candidate
.
attached
||
!
_isInInspectorRenderObjectTree
(
candidate
))
continue
;
candidates
.
add
(
_TransformedRect
(
candidate
));
candidates
.
add
(
_TransformedRect
(
candidate
,
rootRenderObject
));
}
final
_InspectorOverlayRenderState
state
=
_InspectorOverlayRenderState
(
overlayRect:
overlayRect
,
selected:
_TransformedRect
(
selected
),
selected:
_TransformedRect
(
selected
,
rootRenderObject
),
tooltip:
selection
.
currentElement
.
toStringShort
(),
textDirection:
TextDirection
.
ltr
,
candidates:
candidates
,
...
...
@@ -2583,6 +2597,9 @@ class _InspectorOverlayLayer extends Layer {
final
ui
.
PictureRecorder
recorder
=
ui
.
PictureRecorder
();
final
Canvas
canvas
=
Canvas
(
recorder
,
state
.
overlayRect
);
final
Size
size
=
state
.
overlayRect
.
size
;
// The overlay rect could have an offset if the widget inspector does
// not take all the screen.
canvas
.
translate
(
state
.
overlayRect
.
left
,
state
.
overlayRect
.
top
);
final
Paint
fillPaint
=
Paint
()
..
style
=
PaintingStyle
.
fill
...
...
@@ -2695,6 +2712,24 @@ class _InspectorOverlayLayer extends Layer {
})
{
return
false
;
}
/// Return whether or not a render object belongs to this inspector widget
/// tree.
/// The inspector selection is static, so if there are multiple inspector
/// overlays in the same app (i.e. an storyboard), a selected or candidate
/// render object may not belong to this tree.
bool
_isInInspectorRenderObjectTree
(
RenderObject
child
)
{
RenderObject
current
=
child
.
parent
as
RenderObject
;
while
(
current
!=
null
)
{
// We found the widget inspector render object.
if
(
current
is
RenderStack
&&
current
.
lastChild
is
_RenderInspectorOverlay
)
{
return
rootRenderObject
==
current
;
}
current
=
current
.
parent
as
RenderObject
;
}
return
false
;
}
}
const
double
_kScreenEdgeMargin
=
10.0
;
...
...
packages/flutter/test/widgets/widget_inspector_test.dart
View file @
6d303af9
...
...
@@ -512,6 +512,123 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
expect
(
inspectorState
.
selection
.
candidates
.
where
((
RenderObject
object
)
=>
object
is
RenderParagraph
).
length
,
equals
(
2
));
});
testWidgets
(
'WidgetInspector with Transform above'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
childKey
=
GlobalKey
();
final
GlobalKey
repaintBoundaryKey
=
GlobalKey
();
final
Matrix4
mainTransform
=
Matrix4
.
identity
()
..
translate
(
50.0
,
30.0
)
..
scale
(
0.8
,
0.8
)
..
translate
(
100.0
,
50.0
);
await
tester
.
pumpWidget
(
RepaintBoundary
(
key:
repaintBoundaryKey
,
child:
Container
(
color:
Colors
.
grey
,
child:
Transform
(
transform:
mainTransform
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
WidgetInspector
(
selectButtonBuilder:
null
,
child:
Container
(
color:
Colors
.
white
,
child:
Center
(
child:
Container
(
key:
childKey
,
height:
100.0
,
width:
50.0
,
color:
Colors
.
red
,
),
),
),
),
),
),
),
),
);
await
tester
.
tap
(
find
.
byKey
(
childKey
));
await
tester
.
pump
();
await
expectLater
(
find
.
byKey
(
repaintBoundaryKey
),
matchesGoldenFile
(
'inspector.overlay_positioning_with_transform.png'
),
);
});
testWidgets
(
'Multiple widget inspectors'
,
(
WidgetTester
tester
)
async
{
// This test verifies that interacting with different inspectors
// works correctly. This use case may be an app that displays multiple
// apps inside (i.e. a storyboard).
final
GlobalKey
selectButton1Key
=
GlobalKey
();
final
GlobalKey
selectButton2Key
=
GlobalKey
();
final
GlobalKey
inspector1Key
=
GlobalKey
();
final
GlobalKey
inspector2Key
=
GlobalKey
();
final
GlobalKey
child1Key
=
GlobalKey
();
final
GlobalKey
child2Key
=
GlobalKey
();
InspectorSelectButtonBuilder
selectButtonBuilder
(
Key
key
)
{
return
(
BuildContext
context
,
VoidCallback
onPressed
)
{
return
Material
(
child:
RaisedButton
(
onPressed:
onPressed
,
key:
key
));
};
}
// State type is private, hence using dynamic.
// The inspector state is static, so it's enough with reading one of them.
dynamic
getInspectorState
()
=>
inspector1Key
.
currentState
;
String
paragraphText
(
RenderParagraph
paragraph
)
{
final
TextSpan
textSpan
=
paragraph
.
text
as
TextSpan
;
return
textSpan
.
text
;
}
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Row
(
children:
<
Widget
>[
Flexible
(
child:
WidgetInspector
(
key:
inspector1Key
,
selectButtonBuilder:
selectButtonBuilder
(
selectButton1Key
),
child:
Container
(
key:
child1Key
,
child:
const
Text
(
'Child 1'
),
),
),
),
Flexible
(
child:
WidgetInspector
(
key:
inspector2Key
,
selectButtonBuilder:
selectButtonBuilder
(
selectButton2Key
),
child:
Container
(
key:
child2Key
,
child:
const
Text
(
'Child 2'
),
),
),
),
],
),
),
);
final
InspectorSelection
selection
=
getInspectorState
().
selection
as
InspectorSelection
;
// The selection is static, so it may be initialized from previous tests.
selection
?.
clear
();
await
tester
.
tap
(
find
.
text
(
'Child 1'
));
await
tester
.
pump
();
expect
(
paragraphText
(
selection
.
current
as
RenderParagraph
),
equals
(
'Child 1'
));
await
tester
.
tap
(
find
.
text
(
'Child 2'
));
await
tester
.
pump
();
expect
(
paragraphText
(
selection
.
current
as
RenderParagraph
),
equals
(
'Child 2'
));
});
test
(
'WidgetInspectorService null id'
,
()
{
service
.
disposeAllGroups
();
expect
(
service
.
toObject
(
null
),
isNull
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment