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
72517f0a
Unverified
Commit
72517f0a
authored
Feb 10, 2018
by
Michael Goderbauer
Committed by
GitHub
Feb 10, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Encode scrolling status into tree (#14536)
parent
248919fa
Changes
10
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
317 additions
and
170 deletions
+317
-170
engine.version
bin/internal/engine.version
+1
-1
utils.dart
packages/flutter/lib/src/physics/utils.dart
+1
-1
semantics.dart
packages/flutter/lib/src/semantics/semantics.dart
+156
-2
semantics_event.dart
packages/flutter/lib/src/semantics/semantics_event.dart
+0
-70
scroll_metrics.dart
packages/flutter/lib/src/widgets/scroll_metrics.dart
+5
-1
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+39
-34
utils_test.dart
packages/flutter/test/physics/utils_test.dart
+19
-0
semantics_test.dart
packages/flutter/test/semantics/semantics_test.dart
+2
-2
scrollable_semantics_test.dart
packages/flutter/test/widgets/scrollable_semantics_test.dart
+62
-58
semantics_tester.dart
packages/flutter/test/widgets/semantics_tester.dart
+32
-1
No files found.
bin/internal/engine.version
View file @
72517f0a
a031239a5d4e44e60d0ebc62b8c544a9f592fc22
8ac6f6efa177fb548dcdc81f1501f060b2ad1115
packages/flutter/lib/src/physics/utils.dart
View file @
72517f0a
...
@@ -12,7 +12,7 @@ bool nearEqual(double a, double b, double epsilon) {
...
@@ -12,7 +12,7 @@ bool nearEqual(double a, double b, double epsilon) {
assert
(
epsilon
>=
0.0
);
assert
(
epsilon
>=
0.0
);
if
(
a
==
null
||
b
==
null
)
if
(
a
==
null
||
b
==
null
)
return
a
==
b
;
return
a
==
b
;
return
(
a
>
(
b
-
epsilon
))
&&
(
a
<
(
b
+
epsilon
));
return
(
a
>
(
b
-
epsilon
))
&&
(
a
<
(
b
+
epsilon
))
||
a
==
b
;
}
}
/// Whether a double is within a given distance of zero.
/// Whether a double is within a given distance of zero.
...
...
packages/flutter/lib/src/semantics/semantics.dart
View file @
72517f0a
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/semantics/semantics_event.dart
View file @
72517f0a
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/painting.dart'
;
/// An event sent by the application to notify interested listeners that
/// An event sent by the application to notify interested listeners that
...
@@ -53,75 +52,6 @@ abstract class SemanticsEvent {
...
@@ -53,75 +52,6 @@ abstract class SemanticsEvent {
}
}
}
}
/// Notifies that a scroll action has been completed.
///
/// This event translates into a `AccessibilityEvent.TYPE_VIEW_SCROLLED` on
/// Android and a `UIAccessibilityPageScrolledNotification` on iOS. It is
/// processed by the accessibility systems of the operating system to provide
/// additional feedback to the user about the state of a scrollable view (e.g.
/// on Android, a ping sound is played to indicate that a scroll action was
/// successful).
class
ScrollCompletedSemanticsEvent
extends
SemanticsEvent
{
/// Creates a [ScrollCompletedSemanticsEvent].
///
/// This event should be sent after a scroll action is completed. It is
/// interpreted by assistive technologies to provide additional feedback about
/// the just completed scroll action to the user.
///
/// The parameters [axis], [pixels], [minScrollExtent], and [maxScrollExtent] are
/// required and may not be null.
ScrollCompletedSemanticsEvent
({
@required
this
.
axis
,
@required
this
.
pixels
,
@required
this
.
maxScrollExtent
,
@required
this
.
minScrollExtent
})
:
assert
(
axis
!=
null
),
assert
(
pixels
!=
null
),
assert
(
maxScrollExtent
!=
null
),
assert
(
minScrollExtent
!=
null
),
super
(
'scroll'
);
/// The axis in which the scroll view was scrolled.
///
/// See also [ScrollPosition.axis].
final
Axis
axis
;
/// The current scroll position, in logical pixels.
///
/// See also [ScrollPosition.pixels].
final
double
pixels
;
/// The minimum in-range value for [pixels].
///
/// See also [ScrollPosition.minScrollExtent].
final
double
minScrollExtent
;
/// The maximum in-range value for [pixels].
///
/// See also [ScrollPosition.maxScrollExtent].
final
double
maxScrollExtent
;
@override
Map
<
String
,
dynamic
>
getDataMap
()
{
final
Map
<
String
,
dynamic
>
map
=
<
String
,
dynamic
>{
'pixels'
:
pixels
.
clamp
(
minScrollExtent
,
maxScrollExtent
),
'minScrollExtent'
:
minScrollExtent
,
'maxScrollExtent'
:
maxScrollExtent
,
};
switch
(
axis
)
{
case
Axis
.
horizontal
:
map
[
'axis'
]
=
'h'
;
break
;
case
Axis
.
vertical
:
map
[
'axis'
]
=
'v'
;
break
;
}
return
map
;
}
}
/// An event for a semantic announcement.
/// An event for a semantic announcement.
///
///
/// This should be used for announcement that are not seamlessly announced by
/// This should be used for announcement that are not seamlessly announced by
...
...
packages/flutter/lib/src/widgets/scroll_metrics.dart
View file @
72517f0a
...
@@ -59,11 +59,15 @@ abstract class ScrollMetrics {
...
@@ -59,11 +59,15 @@ abstract class ScrollMetrics {
/// The minimum in-range value for [pixels].
/// The minimum in-range value for [pixels].
///
///
/// The actual [pixels] value might be [outOfRange].
/// The actual [pixels] value might be [outOfRange].
///
/// This value can be negative infinity, if the scroll is unbounded.
double
get
minScrollExtent
;
double
get
minScrollExtent
;
/// The maximum in-range value for [pixels].
/// The maximum in-range value for [pixels].
///
///
/// The actual [pixels] value might be [outOfRange].
/// The actual [pixels] value might be [outOfRange].
///
/// This value can be infinity, if the scroll is unbounded.
double
get
maxScrollExtent
;
double
get
maxScrollExtent
;
/// The current scroll position, in logical pixels along the [axisDirection].
/// The current scroll position, in logical pixels along the [axisDirection].
...
...
packages/flutter/lib/src/widgets/scrollable.dart
View file @
72517f0a
...
@@ -275,7 +275,6 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
...
@@ -275,7 +275,6 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
final
ScrollPosition
oldPosition
=
position
;
final
ScrollPosition
oldPosition
=
position
;
if
(
oldPosition
!=
null
)
{
if
(
oldPosition
!=
null
)
{
controller
?.
detach
(
oldPosition
);
controller
?.
detach
(
oldPosition
);
oldPosition
.
removeListener
(
_sendSemanticsScrollEvent
);
// It's important that we not dispose the old position until after the
// It's important that we not dispose the old position until after the
// viewport has had a chance to unregister its listeners from the old
// viewport has had a chance to unregister its listeners from the old
// position. So, schedule a microtask to do it.
// position. So, schedule a microtask to do it.
...
@@ -284,30 +283,10 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
...
@@ -284,30 +283,10 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
_position
=
controller
?.
createScrollPosition
(
_physics
,
this
,
oldPosition
)
_position
=
controller
?.
createScrollPosition
(
_physics
,
this
,
oldPosition
)
??
new
ScrollPositionWithSingleContext
(
physics:
_physics
,
context:
this
,
oldPosition:
oldPosition
);
??
new
ScrollPositionWithSingleContext
(
physics:
_physics
,
context:
this
,
oldPosition:
oldPosition
);
_position
.
addListener
(
_sendSemanticsScrollEvent
);
assert
(
position
!=
null
);
assert
(
position
!=
null
);
controller
?.
attach
(
position
);
controller
?.
attach
(
position
);
}
}
bool
_semanticsScrollEventScheduled
=
false
;
void
_sendSemanticsScrollEvent
()
{
if
(
_semanticsScrollEventScheduled
)
return
;
SchedulerBinding
.
instance
.
addPostFrameCallback
((
Duration
timestamp
)
{
final
_RenderExcludableScrollSemantics
render
=
_excludableScrollSemanticsKey
.
currentContext
?.
findRenderObject
();
render
?.
sendSemanticsEvent
(
new
ScrollCompletedSemanticsEvent
(
axis:
position
.
axis
,
pixels:
position
.
pixels
,
minScrollExtent:
position
.
minScrollExtent
,
maxScrollExtent:
position
.
maxScrollExtent
,
));
_semanticsScrollEventScheduled
=
false
;
});
_semanticsScrollEventScheduled
=
true
;
}
@override
@override
void
didChangeDependencies
()
{
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
super
.
didChangeDependencies
();
...
@@ -529,6 +508,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
...
@@ -529,6 +508,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
result
=
new
_ExcludableScrollSemantics
(
result
=
new
_ExcludableScrollSemantics
(
key:
_excludableScrollSemanticsKey
,
key:
_excludableScrollSemanticsKey
,
child:
result
,
child:
result
,
position:
position
,
);
);
}
}
...
@@ -557,28 +537,61 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
...
@@ -557,28 +537,61 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
/// node, which is annotated with the scrolling actions, will house the
/// node, which is annotated with the scrolling actions, will house the
/// scrollable children.
/// scrollable children.
class
_ExcludableScrollSemantics
extends
SingleChildRenderObjectWidget
{
class
_ExcludableScrollSemantics
extends
SingleChildRenderObjectWidget
{
const
_ExcludableScrollSemantics
({
Key
key
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
const
_ExcludableScrollSemantics
({
Key
key
,
@required
this
.
position
,
Widget
child
})
:
assert
(
position
!=
null
),
super
(
key:
key
,
child:
child
);
final
ScrollPosition
position
;
@override
@override
_RenderExcludableScrollSemantics
createRenderObject
(
BuildContext
context
)
=>
new
_RenderExcludableScrollSemantics
();
_RenderExcludableScrollSemantics
createRenderObject
(
BuildContext
context
)
=>
new
_RenderExcludableScrollSemantics
(
position:
position
);
@override
void
updateRenderObject
(
BuildContext
context
,
_RenderExcludableScrollSemantics
renderObject
)
{
renderObject
.
position
=
position
;
}
}
}
class
_RenderExcludableScrollSemantics
extends
RenderProxyBox
{
class
_RenderExcludableScrollSemantics
extends
RenderProxyBox
{
_RenderExcludableScrollSemantics
({
RenderBox
child
})
:
super
(
child
);
_RenderExcludableScrollSemantics
({
@required
ScrollPosition
position
,
RenderBox
child
,
})
:
_position
=
position
,
assert
(
position
!=
null
),
super
(
child
)
{
position
.
addListener
(
markNeedsSemanticsUpdate
);
}
/// Whether this render object is excluded from the semantic tree.
ScrollPosition
get
position
=>
_position
;
ScrollPosition
_position
;
set
position
(
ScrollPosition
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_position
)
return
;
_position
.
removeListener
(
markNeedsSemanticsUpdate
);
_position
=
value
;
_position
.
addListener
(
markNeedsSemanticsUpdate
);
markNeedsSemanticsUpdate
();
}
@override
@override
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
super
.
describeSemanticsConfiguration
(
config
);
super
.
describeSemanticsConfiguration
(
config
);
config
.
isSemanticBoundary
=
true
;
config
.
isSemanticBoundary
=
true
;
if
(
position
.
haveDimensions
)
{
config
..
scrollPosition
=
_position
.
pixels
..
scrollExtentMax
=
_position
.
maxScrollExtent
..
scrollExtentMin
=
_position
.
minScrollExtent
;
}
}
}
SemanticsNode
_innerNode
;
SemanticsNode
_innerNode
;
SemanticsNode
_annotatedNode
;
@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
))
{
_annotatedNode
=
node
;
super
.
assembleSemanticsNode
(
node
,
config
,
children
);
super
.
assembleSemanticsNode
(
node
,
config
,
children
);
return
;
return
;
}
}
...
@@ -587,7 +600,6 @@ class _RenderExcludableScrollSemantics extends RenderProxyBox {
...
@@ -587,7 +600,6 @@ class _RenderExcludableScrollSemantics extends RenderProxyBox {
_innerNode
_innerNode
..
isMergedIntoParent
=
node
.
isPartOfNodeMerging
..
isMergedIntoParent
=
node
.
isPartOfNodeMerging
..
rect
=
Offset
.
zero
&
node
.
rect
.
size
;
..
rect
=
Offset
.
zero
&
node
.
rect
.
size
;
_annotatedNode
=
_innerNode
;
final
List
<
SemanticsNode
>
excluded
=
<
SemanticsNode
>[
_innerNode
];
final
List
<
SemanticsNode
>
excluded
=
<
SemanticsNode
>[
_innerNode
];
final
List
<
SemanticsNode
>
included
=
<
SemanticsNode
>[];
final
List
<
SemanticsNode
>
included
=
<
SemanticsNode
>[];
...
@@ -606,12 +618,5 @@ class _RenderExcludableScrollSemantics extends RenderProxyBox {
...
@@ -606,12 +618,5 @@ class _RenderExcludableScrollSemantics extends RenderProxyBox {
void
clearSemantics
()
{
void
clearSemantics
()
{
super
.
clearSemantics
();
super
.
clearSemantics
();
_innerNode
=
null
;
_innerNode
=
null
;
_annotatedNode
=
null
;
}
/// Sends a [SemanticsEvent] in the context of the [SemanticsNode] that is
/// annotated with this object's semantics information.
void
sendSemanticsEvent
(
SemanticsEvent
event
)
{
_annotatedNode
?.
sendEvent
(
event
);
}
}
}
}
packages/flutter/test/physics/utils_test.dart
0 → 100644
View file @
72517f0a
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/physics.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
test
(
'nearEquals'
,
()
{
expect
(
nearEqual
(
double
.
infinity
,
double
.
infinity
,
0.1
),
isTrue
);
expect
(
nearEqual
(
double
.
negativeInfinity
,
double
.
negativeInfinity
,
0.1
),
isTrue
);
expect
(
nearEqual
(
double
.
infinity
,
double
.
negativeInfinity
,
0.1
),
isFalse
);
expect
(
nearEqual
(
0.1
,
0.11
,
0.001
),
isFalse
);
expect
(
nearEqual
(
0.1
,
0.11
,
0.1
),
isTrue
);
expect
(
nearEqual
(
0.1
,
0.1
,
0.0000001
),
isTrue
);
});
}
packages/flutter/test/semantics/semantics_test.dart
View file @
72517f0a
...
@@ -348,7 +348,7 @@ void main() {
...
@@ -348,7 +348,7 @@ void main() {
expect
(
expect
(
minimalProperties
.
toStringDeep
(
minLevel:
DiagnosticLevel
.
hidden
),
minimalProperties
.
toStringDeep
(
minLevel:
DiagnosticLevel
.
hidden
),
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isInMutuallyExcusiveGroup: false, isSelected: false, isFocused: false, isButton: false, isTextField: false, invisible, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null, nextNodeId: null, sortOrder: null)
\n
'
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isInMutuallyExcusiveGroup: false, isSelected: false, isFocused: false, isButton: false, isTextField: false, invisible, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null, nextNodeId: null, sortOrder: null
, scrollExtentMin: null, scrollPosition: null, scrollExtentMax: null
)
\n
'
);
);
final
SemanticsConfiguration
config
=
new
SemanticsConfiguration
()
final
SemanticsConfiguration
config
=
new
SemanticsConfiguration
()
...
...
packages/flutter/test/widgets/scrollable_semantics_test.dart
View file @
72517f0a
...
@@ -5,7 +5,6 @@
...
@@ -5,7 +5,6 @@
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'semantics_tester.dart'
;
import
'semantics_tester.dart'
;
...
@@ -204,12 +203,7 @@ void main() {
...
@@ -204,12 +203,7 @@ void main() {
expect
(
tester
.
getTopLeft
(
find
.
byWidget
(
children
[
1
])).
dy
,
kToolbarHeight
);
expect
(
tester
.
getTopLeft
(
find
.
byWidget
(
children
[
1
])).
dy
,
kToolbarHeight
);
});
});
testWidgets
(
'vertical scrolling sends ScrollCompletedSemanticsEvent'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'correct scrollProgress'
,
(
WidgetTester
tester
)
async
{
final
List
<
dynamic
>
messages
=
<
dynamic
>[];
SystemChannels
.
accessibility
.
setMockMessageHandler
((
dynamic
message
)
{
messages
.
add
(
message
);
});
semantics
=
new
SemanticsTester
(
tester
);
semantics
=
new
SemanticsTester
(
tester
);
final
List
<
Widget
>
textWidgets
=
<
Widget
>[];
final
List
<
Widget
>
textWidgets
=
<
Widget
>[];
...
@@ -220,74 +214,84 @@ void main() {
...
@@ -220,74 +214,84 @@ void main() {
child:
new
ListView
(
children:
textWidgets
),
child:
new
ListView
(
children:
textWidgets
),
));
));
await
flingUp
(
tester
);
expect
(
semantics
,
includesNodeWith
(
scrollExtentMin:
0.0
,
expect
(
messages
,
isNot
(
hasLength
(
0
)));
scrollPosition:
0.0
,
expect
(
messages
.
every
((
dynamic
message
)
=>
message
[
'type'
]
==
'scroll'
),
isTrue
);
scrollExtentMax:
520.0
,
actions:
<
SemanticsAction
>[
Map
<
Object
,
Object
>
message
=
messages
.
last
[
'data'
];
SemanticsAction
.
scrollUp
,
expect
(
message
[
'axis'
],
'v'
);
],
expect
(
message
[
'pixels'
],
isPositive
);
));
expect
(
message
[
'minScrollExtent'
],
0.0
);
expect
(
message
[
'maxScrollExtent'
],
520.0
);
messages
.
clear
();
await
flingUp
(
tester
);
await
flingDown
(
tester
);
expect
(
messages
,
isNot
(
hasLength
(
0
)));
expect
(
semantics
,
includesNodeWith
(
expect
(
messages
.
every
((
dynamic
message
)
=>
message
[
'type'
]
==
'scroll'
),
isTrue
);
scrollExtentMin:
0.0
,
scrollPosition:
380.2
,
scrollExtentMax:
520.0
,
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollUp
,
SemanticsAction
.
scrollDown
,
],
));
message
=
messages
.
last
[
'data'
];
await
flingUp
(
tester
);
expect
(
message
[
'axis'
],
'v'
);
expect
(
message
[
'pixels'
],
isNonNegative
);
expect
(
message
[
'minScrollExtent'
],
0.0
);
expect
(
message
[
'maxScrollExtent'
],
520.0
);
});
testWidgets
(
'horizontal scrolling sends ScrollCompletedSemanticsEvent'
,
(
WidgetTester
tester
)
async
{
expect
(
semantics
,
includesNodeWith
(
final
List
<
dynamic
>
messages
=
<
dynamic
>[];
scrollExtentMin:
0.0
,
SystemChannels
.
accessibility
.
setMockMessageHandler
((
dynamic
message
)
{
scrollPosition:
520.0
,
messages
.
add
(
message
);
scrollExtentMax:
520.0
,
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollDown
,
],
));
});
});
testWidgets
(
'correct scrollProgress for unbound'
,
(
WidgetTester
tester
)
async
{
semantics
=
new
SemanticsTester
(
tester
);
semantics
=
new
SemanticsTester
(
tester
);
final
List
<
Widget
>
children
=
<
Widget
>[];
for
(
int
i
=
0
;
i
<
80
;
i
++)
children
.
add
(
new
Container
(
child:
new
Text
(
'
$i
'
),
width:
100.0
,
));
await
tester
.
pumpWidget
(
new
Directionality
(
await
tester
.
pumpWidget
(
new
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
new
ListView
(
child:
new
ListView
.
builder
(
children:
children
,
itemExtent:
20.0
,
scrollDirection:
Axis
.
horizontal
,
itemBuilder:
(
BuildContext
context
,
int
index
)
{
return
new
Text
(
'entry
$index
'
);
},
),
),
));
));
await
flingLeft
(
tester
);
expect
(
semantics
,
includesNodeWith
(
scrollExtentMin:
0.0
,
expect
(
messages
,
isNot
(
hasLength
(
0
)));
scrollPosition:
0.0
,
expect
(
messages
.
every
((
dynamic
message
)
=>
message
[
'type'
]
==
'scroll'
),
isTrue
);
scrollExtentMax:
double
.
infinity
,
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollUp
,
],
));
Map
<
Object
,
Object
>
message
=
messages
.
last
[
'data'
];
await
flingUp
(
tester
);
expect
(
message
[
'axis'
],
'h'
);
expect
(
message
[
'pixels'
],
isPositive
);
expect
(
message
[
'minScrollExtent'
],
0.0
);
expect
(
message
[
'maxScrollExtent'
],
7200.0
);
messages
.
clear
();
expect
(
semantics
,
includesNodeWith
(
await
flingRight
(
tester
);
scrollExtentMin:
0.0
,
scrollPosition:
380.2
,
scrollExtentMax:
double
.
infinity
,
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollUp
,
SemanticsAction
.
scrollDown
,
],
));
expect
(
messages
,
isNot
(
hasLength
(
0
)));
await
flingUp
(
tester
);
expect
(
messages
.
every
((
dynamic
message
)
=>
message
[
'type'
]
==
'scroll'
),
isTrue
);
message
=
messages
.
last
[
'data'
];
expect
(
semantics
,
includesNodeWith
(
expect
(
message
[
'axis'
],
'h'
);
scrollExtentMin:
0.0
,
expect
(
message
[
'pixels'
],
isNonNegative
);
scrollPosition:
760.4
,
expect
(
message
[
'minScrollExtent'
],
0.0
);
scrollExtentMax:
double
.
infinity
,
expect
(
message
[
'maxScrollExtent'
],
7200.0
);
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollUp
,
SemanticsAction
.
scrollDown
,
],
));
});
});
testWidgets
(
'Semantics tree is populated mid-scroll'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Semantics tree is populated mid-scroll'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/widgets/semantics_tester.dart
View file @
72517f0a
...
@@ -5,6 +5,7 @@
...
@@ -5,6 +5,7 @@
import
'dart:ui'
show
SemanticsFlag
;
import
'dart:ui'
show
SemanticsFlag
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/physics.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
...
@@ -369,6 +370,9 @@ class SemanticsTester {
...
@@ -369,6 +370,9 @@ class SemanticsTester {
TextDirection
textDirection
,
TextDirection
textDirection
,
List
<
SemanticsAction
>
actions
,
List
<
SemanticsAction
>
actions
,
List
<
SemanticsFlag
>
flags
,
List
<
SemanticsFlag
>
flags
,
double
scrollPosition
,
double
scrollExtentMax
,
double
scrollExtentMin
,
SemanticsNode
ancestor
,
SemanticsNode
ancestor
,
})
{
})
{
bool
checkNode
(
SemanticsNode
node
)
{
bool
checkNode
(
SemanticsNode
node
)
{
...
@@ -390,6 +394,12 @@ class SemanticsTester {
...
@@ -390,6 +394,12 @@ class SemanticsTester {
if
(
expectedFlags
!=
actualFlags
)
if
(
expectedFlags
!=
actualFlags
)
return
false
;
return
false
;
}
}
if
(
scrollPosition
!=
null
&&
!
nearEqual
(
node
.
scrollPosition
,
scrollPosition
,
0.1
))
return
false
;
if
(
scrollExtentMax
!=
null
&&
!
nearEqual
(
node
.
scrollExtentMax
,
scrollExtentMax
,
0.1
))
return
false
;
if
(
scrollExtentMin
!=
null
&&
!
nearEqual
(
node
.
scrollExtentMin
,
scrollExtentMin
,
0.1
))
return
false
;
return
true
;
return
true
;
}
}
...
@@ -578,13 +588,19 @@ class _IncludesNodeWith extends Matcher {
...
@@ -578,13 +588,19 @@ class _IncludesNodeWith extends Matcher {
this
.
textDirection
,
this
.
textDirection
,
this
.
actions
,
this
.
actions
,
this
.
flags
,
this
.
flags
,
})
:
assert
(
label
!=
null
||
value
!=
null
||
actions
!=
null
||
flags
!=
null
);
this
.
scrollPosition
,
this
.
scrollExtentMax
,
this
.
scrollExtentMin
,
})
:
assert
(
label
!=
null
||
value
!=
null
||
actions
!=
null
||
flags
!=
null
||
scrollPosition
!=
null
||
scrollExtentMax
!=
null
||
scrollExtentMin
!=
null
);
final
String
label
;
final
String
label
;
final
String
value
;
final
String
value
;
final
TextDirection
textDirection
;
final
TextDirection
textDirection
;
final
List
<
SemanticsAction
>
actions
;
final
List
<
SemanticsAction
>
actions
;
final
List
<
SemanticsFlag
>
flags
;
final
List
<
SemanticsFlag
>
flags
;
final
double
scrollPosition
;
final
double
scrollExtentMax
;
final
double
scrollExtentMin
;
@override
@override
bool
matches
(
covariant
SemanticsTester
item
,
Map
<
dynamic
,
dynamic
>
matchState
)
{
bool
matches
(
covariant
SemanticsTester
item
,
Map
<
dynamic
,
dynamic
>
matchState
)
{
...
@@ -594,6 +610,9 @@ class _IncludesNodeWith extends Matcher {
...
@@ -594,6 +610,9 @@ class _IncludesNodeWith extends Matcher {
textDirection:
textDirection
,
textDirection:
textDirection
,
actions:
actions
,
actions:
actions
,
flags:
flags
,
flags:
flags
,
scrollPosition:
scrollPosition
,
scrollExtentMax:
scrollExtentMax
,
scrollExtentMin:
scrollExtentMin
,
).
isNotEmpty
;
).
isNotEmpty
;
}
}
...
@@ -619,6 +638,12 @@ class _IncludesNodeWith extends Matcher {
...
@@ -619,6 +638,12 @@ class _IncludesNodeWith extends Matcher {
strings
.
add
(
'actions "
${actions.join(', ')}
"'
);
strings
.
add
(
'actions "
${actions.join(', ')}
"'
);
if
(
flags
!=
null
)
if
(
flags
!=
null
)
strings
.
add
(
'flags "
${flags.join(', ')}
"'
);
strings
.
add
(
'flags "
${flags.join(', ')}
"'
);
if
(
scrollPosition
!=
null
)
strings
.
add
(
'scrollPosition "
$scrollPosition
"'
);
if
(
scrollExtentMax
!=
null
)
strings
.
add
(
'scrollExtentMax "
$scrollExtentMax
"'
);
if
(
scrollExtentMin
!=
null
)
strings
.
add
(
'scrollExtentMin "
$scrollExtentMin
"'
);
return
strings
.
join
(
', '
);
return
strings
.
join
(
', '
);
}
}
}
}
...
@@ -633,6 +658,9 @@ Matcher includesNodeWith({
...
@@ -633,6 +658,9 @@ Matcher includesNodeWith({
TextDirection
textDirection
,
TextDirection
textDirection
,
List
<
SemanticsAction
>
actions
,
List
<
SemanticsAction
>
actions
,
List
<
SemanticsFlag
>
flags
,
List
<
SemanticsFlag
>
flags
,
double
scrollPosition
,
double
scrollExtentMax
,
double
scrollExtentMin
,
})
{
})
{
return
new
_IncludesNodeWith
(
return
new
_IncludesNodeWith
(
label:
label
,
label:
label
,
...
@@ -640,5 +668,8 @@ Matcher includesNodeWith({
...
@@ -640,5 +668,8 @@ Matcher includesNodeWith({
textDirection:
textDirection
,
textDirection:
textDirection
,
actions:
actions
,
actions:
actions
,
flags:
flags
,
flags:
flags
,
scrollPosition:
scrollPosition
,
scrollExtentMax:
scrollExtentMax
,
scrollExtentMin:
scrollExtentMin
,
);
);
}
}
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