mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Include platformViewId in semantics tree (#28953)
This commit is contained in:
parent
126c58ef7c
commit
816ae4b193
@ -7,6 +7,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/semantics.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'box.dart';
|
||||
@ -87,6 +88,7 @@ class RenderAndroidView extends RenderBox {
|
||||
_viewController = viewController {
|
||||
_motionEventsDispatcher = _MotionEventsDispatcher(globalToLocal, viewController);
|
||||
updateGestureRecognizers(gestureRecognizers);
|
||||
_viewController.addOnPlatformViewCreatedListener(_onPlatformViewCreated);
|
||||
}
|
||||
|
||||
_PlatformViewState _state = _PlatformViewState.uninitialized;
|
||||
@ -99,10 +101,20 @@ class RenderAndroidView extends RenderBox {
|
||||
/// `viewController` must not be null.
|
||||
set viewController(AndroidViewController viewController) {
|
||||
assert(_viewController != null);
|
||||
assert(viewController != null);
|
||||
if (_viewController == viewController)
|
||||
return;
|
||||
_viewController.removeOnPlatformViewCreatedListener(_onPlatformViewCreated);
|
||||
_viewController = viewController;
|
||||
_sizePlatformView();
|
||||
if (_viewController.isCreated) {
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
_viewController.addOnPlatformViewCreatedListener(_onPlatformViewCreated);
|
||||
}
|
||||
|
||||
void _onPlatformViewCreated(int id) {
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// How to behave during hit testing.
|
||||
@ -235,6 +247,17 @@ class RenderAndroidView extends RenderBox {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration (SemanticsConfiguration config) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
|
||||
config.isSemanticBoundary = true;
|
||||
|
||||
if (_viewController.isCreated) {
|
||||
config.platformViewId = _viewController.id;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void detach() {
|
||||
_gestureRecognizer.reset();
|
||||
@ -286,9 +309,9 @@ class RenderUiKitView extends RenderBox {
|
||||
/// must have been created by calling [PlatformViewsService.initUiKitView].
|
||||
UiKitViewController get viewController => _viewController;
|
||||
UiKitViewController _viewController;
|
||||
set viewController(UiKitViewController viewId) {
|
||||
assert(viewId != null);
|
||||
_viewController = viewId;
|
||||
set viewController(UiKitViewController viewController) {
|
||||
assert(viewController != null);
|
||||
_viewController = viewController;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,7 @@ class SemanticsData extends Diagnosticable {
|
||||
@required this.scrollPosition,
|
||||
@required this.scrollExtentMax,
|
||||
@required this.scrollExtentMin,
|
||||
@required this.platformViewId,
|
||||
this.tags,
|
||||
this.transform,
|
||||
this.customSemanticsActionIds,
|
||||
@ -295,6 +296,19 @@ class SemanticsData extends Diagnosticable {
|
||||
/// * [ScrollPosition.minScrollExtent], from where this value is usually taken.
|
||||
final double scrollExtentMin;
|
||||
|
||||
/// The id of the platform view, whose semantics nodes will be added as
|
||||
/// children to this node.
|
||||
///
|
||||
/// If this value is non-null, the SemanticsNode must not have any children
|
||||
/// as those would be replaced by the semantics nodes of the referenced
|
||||
/// platform view.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AndroidView], which is the platform view for Android.
|
||||
/// * [UiKitView], which is the platform view for iOS.
|
||||
final int platformViewId;
|
||||
|
||||
/// The bounding box for this node in its coordinate system.
|
||||
final Rect rect;
|
||||
|
||||
@ -374,6 +388,7 @@ class SemanticsData extends Diagnosticable {
|
||||
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
||||
if (textSelection?.isValid == true)
|
||||
properties.add(MessageProperty('textSelection', '[${textSelection.start}, ${textSelection.end}]'));
|
||||
properties.add(IntProperty('platformViewId', platformViewId, defaultValue: null));
|
||||
properties.add(IntProperty('scrollChildren', scrollChildCount, defaultValue: null));
|
||||
properties.add(IntProperty('scrollIndex', scrollIndex, defaultValue: null));
|
||||
properties.add(DoubleProperty('scrollExtentMin', scrollExtentMin, defaultValue: null));
|
||||
@ -402,6 +417,7 @@ class SemanticsData extends Diagnosticable {
|
||||
&& typedOther.scrollPosition == scrollPosition
|
||||
&& typedOther.scrollExtentMax == scrollExtentMax
|
||||
&& typedOther.scrollExtentMin == scrollExtentMin
|
||||
&& typedOther.platformViewId == platformViewId
|
||||
&& typedOther.transform == transform
|
||||
&& typedOther.elevation == elevation
|
||||
&& typedOther.thickness == thickness
|
||||
@ -411,25 +427,28 @@ class SemanticsData extends Diagnosticable {
|
||||
@override
|
||||
int get hashCode {
|
||||
return ui.hashValues(
|
||||
flags,
|
||||
actions,
|
||||
label,
|
||||
value,
|
||||
increasedValue,
|
||||
decreasedValue,
|
||||
hint,
|
||||
textDirection,
|
||||
rect,
|
||||
tags,
|
||||
textSelection,
|
||||
scrollChildCount,
|
||||
scrollIndex,
|
||||
scrollPosition,
|
||||
scrollExtentMax,
|
||||
scrollExtentMin,
|
||||
transform,
|
||||
elevation,
|
||||
thickness,
|
||||
ui.hashValues(
|
||||
flags,
|
||||
actions,
|
||||
label,
|
||||
value,
|
||||
increasedValue,
|
||||
decreasedValue,
|
||||
hint,
|
||||
textDirection,
|
||||
rect,
|
||||
tags,
|
||||
textSelection,
|
||||
scrollChildCount,
|
||||
scrollIndex,
|
||||
scrollPosition,
|
||||
scrollExtentMax,
|
||||
scrollExtentMin,
|
||||
platformViewId,
|
||||
transform,
|
||||
elevation,
|
||||
thickness,
|
||||
),
|
||||
ui.hashList(customSemanticsActionIds),
|
||||
);
|
||||
}
|
||||
@ -1464,6 +1483,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
_scrollExtentMin != config._scrollExtentMin ||
|
||||
_actionsAsBits != config._actionsAsBits ||
|
||||
indexInParent != config.indexInParent ||
|
||||
platformViewId != config.platformViewId ||
|
||||
_mergeAllDescendantsIntoThisNode != config.isMergingSemanticsOfDescendants;
|
||||
}
|
||||
|
||||
@ -1663,6 +1683,20 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
double get scrollExtentMin => _scrollExtentMin;
|
||||
double _scrollExtentMin;
|
||||
|
||||
/// The id of the platform view, whose semantics nodes will be added as
|
||||
/// children to this node.
|
||||
///
|
||||
/// If this value is non-null, the SemanticsNode must not have any children
|
||||
/// as those would be replaced by the semantics nodes of the referenced
|
||||
/// platform view.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AndroidView], which is the platform view for Android.
|
||||
/// * [UiKitView], which is the platform view for iOS.
|
||||
int get platformViewId => _platformViewId;
|
||||
int _platformViewId;
|
||||
|
||||
bool _canPerformAction(SemanticsAction action) => _actions.containsKey(action);
|
||||
|
||||
static final SemanticsConfiguration _kEmptyConfig = SemanticsConfiguration();
|
||||
@ -1684,6 +1718,11 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
if (_isDifferentFromCurrentSemanticAnnotation(config))
|
||||
_markDirty();
|
||||
|
||||
assert(
|
||||
config.platformViewId == null || childrenInInversePaintOrder.isEmpty,
|
||||
'SemanticsNodes with children must not specify a platformViewId.'
|
||||
);
|
||||
|
||||
_label = config.label;
|
||||
_decreasedValue = config.decreasedValue;
|
||||
_value = config.value;
|
||||
@ -1706,6 +1745,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
_scrollChildCount = config.scrollChildCount;
|
||||
_scrollIndex = config.scrollIndex;
|
||||
indexInParent = config.indexInParent;
|
||||
_platformViewId = config._platformViewId;
|
||||
_replaceChildren(childrenInInversePaintOrder ?? const <SemanticsNode>[]);
|
||||
|
||||
assert(
|
||||
@ -1740,6 +1780,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
double scrollPosition = _scrollPosition;
|
||||
double scrollExtentMax = _scrollExtentMax;
|
||||
double scrollExtentMin = _scrollExtentMin;
|
||||
int platformViewId = _platformViewId;
|
||||
final double elevation = _elevation;
|
||||
double thickness = _thickness;
|
||||
final Set<int> customSemanticsActionIds = <int>{};
|
||||
@ -1774,6 +1815,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
scrollPosition ??= node._scrollPosition;
|
||||
scrollExtentMax ??= node._scrollExtentMax;
|
||||
scrollExtentMin ??= node._scrollExtentMin;
|
||||
platformViewId ??= node._platformViewId;
|
||||
if (value == '' || value == null)
|
||||
value = node._value;
|
||||
if (increasedValue == '' || increasedValue == null)
|
||||
@ -1843,6 +1885,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
scrollPosition: scrollPosition,
|
||||
scrollExtentMax: scrollExtentMax,
|
||||
scrollExtentMin: scrollExtentMin,
|
||||
platformViewId: platformViewId,
|
||||
customSemanticsActionIds: customSemanticsActionIds.toList()..sort(),
|
||||
);
|
||||
}
|
||||
@ -1898,6 +1941,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
textDirection: data.textDirection,
|
||||
textSelectionBase: data.textSelection != null ? data.textSelection.baseOffset : -1,
|
||||
textSelectionExtent: data.textSelection != null ? data.textSelection.extentOffset : -1,
|
||||
platformViewId: data.platformViewId != null ? data.platformViewId : -1,
|
||||
scrollChildren: data.scrollChildCount != null ? data.scrollChildCount : 0,
|
||||
scrollIndex: data.scrollIndex != null ? data.scrollIndex : 0 ,
|
||||
scrollPosition: data.scrollPosition != null ? data.scrollPosition : double.nan,
|
||||
@ -2038,6 +2082,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
properties.add(DiagnosticsProperty<SemanticsSortKey>('sortKey', sortKey, defaultValue: null));
|
||||
if (_textSelection?.isValid == true)
|
||||
properties.add(MessageProperty('text selection', '[${_textSelection.start}, ${_textSelection.end}]'));
|
||||
properties.add(IntProperty('platformViewId', platformViewId, defaultValue: null));
|
||||
properties.add(IntProperty('scrollChildren', scrollChildCount, defaultValue: null));
|
||||
properties.add(IntProperty('scrollIndex', scrollIndex, defaultValue: null));
|
||||
properties.add(DoubleProperty('scrollExtentMin', scrollExtentMin, defaultValue: null));
|
||||
@ -3100,6 +3145,16 @@ class SemanticsConfiguration {
|
||||
_hasBeenAnnotated = true;
|
||||
}
|
||||
|
||||
/// The id of the platform view, whose semantics nodes will be added as
|
||||
/// children to this node.
|
||||
int get platformViewId => _platformViewId;
|
||||
int _platformViewId;
|
||||
set platformViewId(int value) {
|
||||
if (value == platformViewId)
|
||||
return;
|
||||
_platformViewId = value;
|
||||
_hasBeenAnnotated = true;
|
||||
}
|
||||
|
||||
/// Whether the semantic information provided by the owning [RenderObject] and
|
||||
/// all of its descendants should be treated as one logical entity.
|
||||
@ -3583,6 +3638,9 @@ class SemanticsConfiguration {
|
||||
return false;
|
||||
if ((_flags & other._flags) != 0)
|
||||
return false;
|
||||
if (_platformViewId != null && other._platformViewId != null) {
|
||||
return false;
|
||||
}
|
||||
if (_value != null && _value.isNotEmpty && other._value != null && other._value.isNotEmpty)
|
||||
return false;
|
||||
return true;
|
||||
@ -3617,6 +3675,7 @@ class SemanticsConfiguration {
|
||||
_indexInParent ??= child.indexInParent;
|
||||
_scrollIndex ??= child._scrollIndex;
|
||||
_scrollChildCount ??= child._scrollChildCount;
|
||||
_platformViewId ??= child._platformViewId;
|
||||
|
||||
textDirection ??= child.textDirection;
|
||||
_sortKey ??= child._sortKey;
|
||||
@ -3672,6 +3731,7 @@ class SemanticsConfiguration {
|
||||
.._indexInParent = indexInParent
|
||||
.._scrollIndex = _scrollIndex
|
||||
.._scrollChildCount = _scrollChildCount
|
||||
.._platformViewId = _platformViewId
|
||||
.._actions.addAll(_actions)
|
||||
.._customSemanticsActions.addAll(_customSemanticsActions);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ final PlatformViewsRegistry platformViewsRegistry = PlatformViewsRegistry._insta
|
||||
class PlatformViewsRegistry {
|
||||
PlatformViewsRegistry._instance();
|
||||
|
||||
// Always non-negative. The id value -1 is used in the accessibility bridge
|
||||
// to indicate the absence of a platform view.
|
||||
int _nextPlatformViewId = 0;
|
||||
|
||||
/// Allocates a unique identifier for a platform view.
|
||||
@ -77,7 +79,6 @@ class PlatformViewsService {
|
||||
@required TextDirection layoutDirection,
|
||||
dynamic creationParams,
|
||||
MessageCodec<dynamic> creationParamsCodec,
|
||||
PlatformViewCreatedCallback onPlatformViewCreated,
|
||||
}) {
|
||||
assert(id != null);
|
||||
assert(viewType != null);
|
||||
@ -89,7 +90,6 @@ class PlatformViewsService {
|
||||
creationParams,
|
||||
creationParamsCodec,
|
||||
layoutDirection,
|
||||
onPlatformViewCreated,
|
||||
);
|
||||
}
|
||||
|
||||
@ -406,7 +406,6 @@ class AndroidViewController {
|
||||
dynamic creationParams,
|
||||
MessageCodec<dynamic> creationParamsCodec,
|
||||
TextDirection layoutDirection,
|
||||
PlatformViewCreatedCallback onPlatformViewCreated,
|
||||
) : assert(id != null),
|
||||
assert(viewType != null),
|
||||
assert(layoutDirection != null),
|
||||
@ -415,7 +414,6 @@ class AndroidViewController {
|
||||
_creationParams = creationParams,
|
||||
_creationParamsCodec = creationParamsCodec,
|
||||
_layoutDirection = layoutDirection,
|
||||
_onPlatformViewCreated = onPlatformViewCreated,
|
||||
_state = _AndroidViewState.waitingForSize;
|
||||
|
||||
/// Action code for when a primary pointer touched the screen.
|
||||
@ -459,8 +457,6 @@ class AndroidViewController {
|
||||
|
||||
final String _viewType;
|
||||
|
||||
final PlatformViewCreatedCallback _onPlatformViewCreated;
|
||||
|
||||
/// The texture entry id into which the Android view is rendered.
|
||||
int _textureId;
|
||||
|
||||
@ -478,6 +474,25 @@ class AndroidViewController {
|
||||
|
||||
MessageCodec<dynamic> _creationParamsCodec;
|
||||
|
||||
final List<PlatformViewCreatedCallback> _platformViewCreatedCallbacks = <PlatformViewCreatedCallback>[];
|
||||
|
||||
/// Whether the platform view has already been created.
|
||||
bool get isCreated => _state == _AndroidViewState.created;
|
||||
|
||||
/// Adds a callback that will get invoke after the platform view has been
|
||||
/// created.
|
||||
void addOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {
|
||||
assert(listener != null);
|
||||
assert(_state != _AndroidViewState.disposed);
|
||||
_platformViewCreatedCallbacks.add(listener);
|
||||
}
|
||||
|
||||
/// Removes a callback added with [addOnPlatformViewCreatedListener].
|
||||
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {
|
||||
assert(_state != _AndroidViewState.disposed);
|
||||
_platformViewCreatedCallbacks.remove(listener);
|
||||
}
|
||||
|
||||
/// Disposes the Android view.
|
||||
///
|
||||
/// The [AndroidViewController] object is unusable after calling this.
|
||||
@ -486,6 +501,7 @@ class AndroidViewController {
|
||||
Future<void> dispose() async {
|
||||
if (_state == _AndroidViewState.creating || _state == _AndroidViewState.created)
|
||||
await SystemChannels.platform_views.invokeMethod<void>('dispose', id);
|
||||
_platformViewCreatedCallbacks.clear();
|
||||
_state = _AndroidViewState.disposed;
|
||||
}
|
||||
|
||||
@ -578,9 +594,10 @@ class AndroidViewController {
|
||||
);
|
||||
}
|
||||
_textureId = await SystemChannels.platform_views.invokeMethod('create', args);
|
||||
if (_onPlatformViewCreated != null)
|
||||
_onPlatformViewCreated(id);
|
||||
_state = _AndroidViewState.created;
|
||||
for (PlatformViewCreatedCallback callback in _platformViewCreatedCallbacks) {
|
||||
callback(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,10 +367,12 @@ class _AndroidViewState extends State<AndroidView> {
|
||||
id: _id,
|
||||
viewType: widget.viewType,
|
||||
layoutDirection: _layoutDirection,
|
||||
onPlatformViewCreated: widget.onPlatformViewCreated,
|
||||
creationParams: widget.creationParams,
|
||||
creationParamsCodec: widget.creationParamsCodec,
|
||||
);
|
||||
if (widget.onPlatformViewCreated != null) {
|
||||
_controller.addOnPlatformViewCreatedListener(widget.onPlatformViewCreated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,6 +346,7 @@ void main() {
|
||||
' hint: ""\n'
|
||||
' textDirection: null\n'
|
||||
' sortKey: null\n'
|
||||
' platformViewId: null\n'
|
||||
' scrollChildren: null\n'
|
||||
' scrollIndex: null\n'
|
||||
' scrollExtentMin: null\n'
|
||||
@ -440,6 +441,7 @@ void main() {
|
||||
' hint: ""\n'
|
||||
' textDirection: null\n'
|
||||
' sortKey: null\n'
|
||||
' platformViewId: null\n'
|
||||
' scrollChildren: null\n'
|
||||
' scrollIndex: null\n'
|
||||
' scrollExtentMin: null\n'
|
||||
|
@ -26,6 +26,8 @@ class FakeAndroidPlatformViewsController {
|
||||
|
||||
Completer<void> resizeCompleter;
|
||||
|
||||
Completer<void> createCompleter;
|
||||
|
||||
void registerViewType(String viewType) {
|
||||
_registeredViewTypes.add(viewType);
|
||||
}
|
||||
@ -46,7 +48,7 @@ class FakeAndroidPlatformViewsController {
|
||||
return Future<dynamic>.sync(() => null);
|
||||
}
|
||||
|
||||
Future<dynamic> _create(MethodCall call) {
|
||||
Future<dynamic> _create(MethodCall call) async {
|
||||
final Map<dynamic, dynamic> args = call.arguments;
|
||||
final int id = args['id'];
|
||||
final String viewType = args['viewType'];
|
||||
@ -67,6 +69,10 @@ class FakeAndroidPlatformViewsController {
|
||||
message: 'Trying to create a platform view of unregistered type: $viewType',
|
||||
);
|
||||
|
||||
if (createCompleter != null) {
|
||||
await createCompleter.future;
|
||||
}
|
||||
|
||||
_views[id] = FakeAndroidPlatformView(id, viewType, Size(width, height), layoutDirection, creationParams);
|
||||
final int textureId = _textureCounter++;
|
||||
return Future<int>.sync(() => textureId);
|
||||
|
@ -105,14 +105,20 @@ void main() {
|
||||
final PlatformViewCreatedCallback callback = (int id) { createdViews.add(id); };
|
||||
|
||||
final AndroidViewController controller1 = PlatformViewsService.initAndroidView(
|
||||
id: 0, viewType: 'webview', layoutDirection: TextDirection.ltr, onPlatformViewCreated: callback);
|
||||
id: 0,
|
||||
viewType: 'webview',
|
||||
layoutDirection: TextDirection.ltr,
|
||||
)..addOnPlatformViewCreatedListener(callback);
|
||||
expect(createdViews, isEmpty);
|
||||
|
||||
await controller1.setSize(const Size(100.0, 100.0));
|
||||
expect(createdViews, orderedEquals(<int>[0]));
|
||||
|
||||
final AndroidViewController controller2 = PlatformViewsService.initAndroidView(
|
||||
id: 5, viewType: 'webview', layoutDirection: TextDirection.ltr, onPlatformViewCreated: callback);
|
||||
id: 5,
|
||||
viewType: 'webview',
|
||||
layoutDirection: TextDirection.ltr,
|
||||
)..addOnPlatformViewCreatedListener(callback);
|
||||
expect(createdViews, orderedEquals(<int>[0]));
|
||||
|
||||
await controller2.setSize(const Size(100.0, 200.0));
|
||||
|
@ -806,6 +806,53 @@ void main() {
|
||||
|
||||
expect(factoryInvocationCount, 1);
|
||||
});
|
||||
|
||||
testWidgets('AndroidView has correct semantics', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
|
||||
expect(currentViewId, greaterThanOrEqualTo(0));
|
||||
final FakeAndroidPlatformViewsController viewsController = FakeAndroidPlatformViewsController();
|
||||
viewsController.registerViewType('webview');
|
||||
|
||||
viewsController.createCompleter = Completer<void>();
|
||||
|
||||
await tester.pumpWidget(
|
||||
Semantics(
|
||||
container: true,
|
||||
child: const Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
height: 100.0,
|
||||
child: AndroidView(
|
||||
viewType: 'webview',
|
||||
layoutDirection: TextDirection.ltr,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final SemanticsNode semantics = tester.getSemantics(find.byType(AndroidView));
|
||||
|
||||
// Platform view has not been created yet, no platformViewId.
|
||||
expect(semantics.platformViewId, null);
|
||||
expect(semantics.rect, Rect.fromLTWH(0, 0, 200, 100));
|
||||
// A 200x100 rect positioned at bottom right of a 800x600 box.
|
||||
expect(semantics.transform, Matrix4.translationValues(600, 500, 0));
|
||||
expect(semantics.childrenCount, 0);
|
||||
|
||||
viewsController.createCompleter.complete();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(semantics.platformViewId, currentViewId + 1);
|
||||
expect(semantics.rect, Rect.fromLTWH(0, 0, 200, 100));
|
||||
// A 200x100 rect positioned at bottom right of a 800x600 box.
|
||||
expect(semantics.transform, Matrix4.translationValues(600, 500, 0));
|
||||
expect(semantics.childrenCount, 0);
|
||||
|
||||
handle.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
group('UiKitView', () {
|
||||
|
@ -364,6 +364,7 @@ Matcher matchesSemantics({
|
||||
Size size,
|
||||
double elevation,
|
||||
double thickness,
|
||||
int platformViewId,
|
||||
// Flags //
|
||||
bool hasCheckedState = false,
|
||||
bool isChecked = false,
|
||||
@ -514,6 +515,7 @@ Matcher matchesSemantics({
|
||||
size: size,
|
||||
elevation: elevation,
|
||||
thickness: thickness,
|
||||
platformViewId: platformViewId,
|
||||
customActions: customActions,
|
||||
hintOverrides: hintOverrides,
|
||||
children: children,
|
||||
@ -1698,6 +1700,7 @@ class _MatchesSemanticsData extends Matcher {
|
||||
this.size,
|
||||
this.elevation,
|
||||
this.thickness,
|
||||
this.platformViewId,
|
||||
this.customActions,
|
||||
this.hintOverrides,
|
||||
this.children,
|
||||
@ -1717,6 +1720,7 @@ class _MatchesSemanticsData extends Matcher {
|
||||
final Size size;
|
||||
final double elevation;
|
||||
final double thickness;
|
||||
final int platformViewId;
|
||||
final List<Matcher> children;
|
||||
|
||||
@override
|
||||
@ -1746,6 +1750,8 @@ class _MatchesSemanticsData extends Matcher {
|
||||
description.add(' with elevation: $elevation');
|
||||
if (thickness != null)
|
||||
description.add(' with thickness: $thickness');
|
||||
if (platformViewId != null)
|
||||
description.add(' with platformViewId: $platformViewId');
|
||||
if (customActions != null)
|
||||
description.add(' with custom actions: $customActions');
|
||||
if (hintOverrides != null)
|
||||
@ -1786,6 +1792,8 @@ class _MatchesSemanticsData extends Matcher {
|
||||
return failWithDescription(matchState, 'elevation was: ${data.elevation}');
|
||||
if (thickness != null && thickness != data.thickness)
|
||||
return failWithDescription(matchState, 'thickness was: ${data.thickness}');
|
||||
if (platformViewId != null && platformViewId != data.platformViewId)
|
||||
return failWithDescription(matchState, 'platformViewId was: ${data.platformViewId}');
|
||||
if (actions != null) {
|
||||
int actionBits = 0;
|
||||
for (SemanticsAction action in actions)
|
||||
|
@ -502,6 +502,7 @@ void main() {
|
||||
scrollPosition: null,
|
||||
scrollExtentMax: null,
|
||||
scrollExtentMin: null,
|
||||
platformViewId: 105,
|
||||
customSemanticsActionIds: <int>[CustomSemanticsAction.getIdentifier(action)],
|
||||
);
|
||||
final _FakeSemanticsNode node = _FakeSemanticsNode();
|
||||
@ -512,6 +513,7 @@ void main() {
|
||||
size: const Size(10.0, 10.0),
|
||||
elevation: 3.0,
|
||||
thickness: 4.0,
|
||||
platformViewId: 105,
|
||||
/* Flags */
|
||||
hasCheckedState: true,
|
||||
isChecked: true,
|
||||
|
Loading…
Reference in New Issue
Block a user