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
b20e7a26
Unverified
Commit
b20e7a26
authored
Oct 31, 2018
by
Amir Hardon
Committed by
GitHub
Oct 31, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Initial framework support for iOS platform views. (#23412)" (#23779)
This reverts commit
67ffe1c2
.
parent
67ffe1c2
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
727 additions
and
1450 deletions
+727
-1450
layer.dart
packages/flutter/lib/src/rendering/layer.dart
+0
-34
platform_view.dart
packages/flutter/lib/src/rendering/platform_view.dart
+0
-77
platform_views.dart
packages/flutter/lib/src/services/platform_views.dart
+4
-87
platform_view.dart
packages/flutter/lib/src/widgets/platform_view.dart
+8
-180
fake_platform_views.dart
packages/flutter/test/services/fake_platform_views.dart
+26
-110
platform_views_test.dart
packages/flutter/test/services/platform_views_test.dart
+16
-94
platform_view_test.dart
packages/flutter/test/widgets/platform_view_test.dart
+673
-868
No files found.
packages/flutter/lib/src/rendering/layer.dart
View file @
b20e7a26
...
...
@@ -357,40 +357,6 @@ class TextureLayer extends Layer {
S
find
<
S
>(
Offset
regionOffset
)
=>
null
;
}
/// A layer that shows an embedded [UIView](https://developer.apple.com/documentation/uikit/uiview)
/// on iOS.
class
PlatformViewLayer
extends
Layer
{
/// Creates a platform view layer.
///
/// The `rect` and `viewId` parameters must not be null.
PlatformViewLayer
({
@required
this
.
rect
,
@required
this
.
viewId
,
}):
assert
(
rect
!=
null
),
assert
(
viewId
!=
null
);
/// Bounding rectangle of this layer in the global coordinate space.
final
Rect
rect
;
/// The unique identifier of the UIView displayed on this layer.
///
/// A UIView with this identifier must have been created by [PlatformViewsServices.initUiKitView].
final
int
viewId
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
final
Rect
shiftedRect
=
rect
.
shift
(
layerOffset
);
builder
.
addPlatformView
(
viewId
,
offset:
shiftedRect
.
topLeft
,
width:
shiftedRect
.
width
,
height:
shiftedRect
.
height
,
);
}
@override
S
find
<
S
>(
Offset
regionOffset
)
=>
null
;
}
/// A layer that indicates to the compositor that it should display
/// certain performance statistics within it.
///
...
...
packages/flutter/lib/src/rendering/platform_view.dart
View file @
b20e7a26
...
...
@@ -43,10 +43,8 @@ enum _PlatformViewState {
/// [RenderAndroidView] is responsible for sizing, displaying and passing touch events to an
/// Android [View](https://developer.android.com/reference/android/view/View).
///
/// {@template flutter.rendering.platformView.layout}
/// The render object's layout behavior is to fill all available space, the parent of this object must
/// provide bounded layout constraints.
/// {@endtemplate}
///
/// RenderAndroidView participates in Flutter's [GestureArena]s, and dispatches touch events to the
/// Android view iff it won the arena. Specific gestures that should be dispatched to the Android
...
...
@@ -235,81 +233,6 @@ class RenderAndroidView extends RenderBox {
}
}
/// This is work in progress, not yet ready to be used, and requires a custom engine build. A render object for an iOS UIKit UIView.
///
/// [RenderUiKitView] is responsible for sizing and displaying an iOS
/// [UIView](https://developer.apple.com/documentation/uikit/uiview).
///
/// UIViews are added as sub views of the FlutterView and are composited by Quartz.
///
/// {@macro flutter.rendering.platformView.layout}
///
/// See also:
/// * [UiKitView] which is a widget that is used to show a UIView.
/// * [PlatformViewsService] which is a service for controlling platform views.
class
RenderUiKitView
extends
RenderBox
{
/// Creates a render object for an iOS UIView.
///
/// The `viewId` and `hitTestBehavior` parameters must not be null.
RenderUiKitView
({
@required
int
viewId
,
@required
this
.
hitTestBehavior
,
})
:
assert
(
viewId
!=
null
),
assert
(
hitTestBehavior
!=
null
),
_viewId
=
viewId
;
/// The unique identifier of the UIView controlled by this controller.
///
/// Typically generated by [PlatformViewsRegistry.getNextPlatformViewId], the UIView
/// must have been created by calling [PlatformViewsService.initUiKitView].
int
get
viewId
=>
_viewId
;
int
_viewId
;
set
viewId
(
int
viewId
)
{
assert
(
viewId
!=
null
);
_viewId
=
viewId
;
markNeedsPaint
();
}
/// How to behave during hit testing.
// The implicit setter is enough here as changing this value will just affect
// any newly arriving events there's nothing we need to invalidate.
PlatformViewHitTestBehavior
hitTestBehavior
;
@override
bool
get
sizedByParent
=>
true
;
@override
bool
get
alwaysNeedsCompositing
=>
true
;
@override
bool
get
isRepaintBoundary
=>
true
;
@override
void
performResize
()
{
size
=
constraints
.
biggest
;
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
context
.
addLayer
(
PlatformViewLayer
(
rect:
offset
&
size
,
viewId:
_viewId
,
));
}
@override
bool
hitTest
(
HitTestResult
result
,
{
Offset
position
})
{
if
(
hitTestBehavior
==
PlatformViewHitTestBehavior
.
transparent
||
!
size
.
contains
(
position
))
return
false
;
result
.
add
(
BoxHitTestEntry
(
this
,
position
));
return
hitTestBehavior
==
PlatformViewHitTestBehavior
.
opaque
;
}
@override
bool
hitTestSelf
(
Offset
position
)
=>
hitTestBehavior
!=
PlatformViewHitTestBehavior
.
transparent
;
}
class
_AndroidViewGestureRecognizer
extends
OneSequenceGestureRecognizer
{
_AndroidViewGestureRecognizer
(
this
.
dispatcher
,
this
.
gestureRecognizerFactories
)
{
team
=
GestureArenaTeam
();
...
...
packages/flutter/lib/src/services/platform_views.dart
View file @
b20e7a26
...
...
@@ -91,46 +91,6 @@ class PlatformViewsService {
onPlatformViewCreated
,
);
}
// TODO(amirh): reference the iOS plugin API for registering a UIView factory once it lands.
/// This is work in progress, not yet ready to be used, and requires a custom engine build. Creates a controller for a new iOS UIView.
///
/// `id` is an unused unique identifier generated with [platformViewsRegistry].
///
/// `viewType` is the identifier of the iOS view type to be created, a
/// factory for this view type must have been registered on the platform side.
/// Platform view factories are typically registered by plugin code.
///
/// The `id, `viewType, and `layoutDirection` parameters must not be null.
/// If `creationParams` is non null then `cretaionParamsCodec` must not be null.
static
Future
<
UiKitViewController
>
initUiKitView
({
@required
int
id
,
@required
String
viewType
,
@required
TextDirection
layoutDirection
,
dynamic
creationParams
,
MessageCodec
<
dynamic
>
creationParamsCodec
,
})
async
{
assert
(
id
!=
null
);
assert
(
viewType
!=
null
);
assert
(
layoutDirection
!=
null
);
assert
(
creationParams
==
null
||
creationParamsCodec
!=
null
);
// TODO(amirh): pass layoutDirection once the system channel supports it.
final
Map
<
String
,
dynamic
>
args
=
<
String
,
dynamic
>
{
'id'
:
id
,
'viewType'
:
viewType
,
};
if
(
creationParams
!=
null
)
{
final
ByteData
paramsByteData
=
creationParamsCodec
.
encodeMessage
(
creationParams
);
args
[
'params'
]
=
Uint8List
.
view
(
paramsByteData
.
buffer
,
0
,
paramsByteData
.
lengthInBytes
,
);
}
await
SystemChannels
.
platform_views
.
invokeMethod
(
'create'
,
args
);
return
UiKitViewController
.
_
(
id
,
layoutDirection
);
}
}
/// Properties of an Android pointer.
...
...
@@ -495,7 +455,8 @@ class AndroidViewController {
///
/// The first time a size is set triggers the creation of the Android view.
Future
<
void
>
setSize
(
Size
size
)
async
{
assert
(
_state
!=
_AndroidViewState
.
disposed
,
'trying to size a disposed Android View. View id:
$id
'
);
if
(
_state
==
_AndroidViewState
.
disposed
)
throw
FlutterError
(
'trying to size a disposed Android View. View id:
$id
'
);
assert
(
size
!=
null
);
assert
(!
size
.
isEmpty
);
...
...
@@ -512,7 +473,8 @@ class AndroidViewController {
/// Sets the layout direction for the Android view.
Future
<
void
>
setLayoutDirection
(
TextDirection
layoutDirection
)
async
{
assert
(
_state
!=
_AndroidViewState
.
disposed
,
'trying to set a layout direction for a disposed UIView. View id:
$id
'
);
if
(
_state
==
_AndroidViewState
.
disposed
)
throw
FlutterError
(
'trying to set a layout direction for a disposed Android View. View id:
$id
'
);
if
(
layoutDirection
==
_layoutDirection
)
return
;
...
...
@@ -582,48 +544,3 @@ class AndroidViewController {
_state
=
_AndroidViewState
.
created
;
}
}
/// Controls an iOS UIView.
///
/// Typically created with [PlatformViewsService.initUiKitView].
class
UiKitViewController
{
UiKitViewController
.
_
(
this
.
id
,
TextDirection
layoutDirection
,
)
:
assert
(
id
!=
null
),
assert
(
layoutDirection
!=
null
),
_layoutDirection
=
layoutDirection
;
/// The unique identifier of the iOS view controlled by this controller.
///
/// This identifer is typically generated by [PlatformViewsRegistry.getNextPlatformViewId].
final
int
id
;
bool
_debugDisposed
=
false
;
TextDirection
_layoutDirection
;
/// Sets the layout direction for the Android view.
Future
<
void
>
setLayoutDirection
(
TextDirection
layoutDirection
)
async
{
assert
(!
_debugDisposed
,
'trying to set a layout direction for a disposed Android View. View id:
$id
'
);
if
(
layoutDirection
==
_layoutDirection
)
return
;
assert
(
layoutDirection
!=
null
);
_layoutDirection
=
layoutDirection
;
// TODO(amirh): invoke the iOS platform views channel direction method once available.
}
/// Disposes the view.
///
/// The [UiKitViewController] object is unusable after calling this.
/// The `id` of the platform view cannot be reused after the view is
/// disposed.
Future
<
void
>
dispose
()
async
{
_debugDisposed
=
true
;
await
SystemChannels
.
platform_views
.
invokeMethod
(
'dispose'
,
id
);
}
}
packages/flutter/lib/src/widgets/platform_view.dart
View file @
b20e7a26
...
...
@@ -21,10 +21,8 @@ import 'framework.dart';
/// The embedded Android view is painted just like any other Flutter widget and transformations
/// apply to it as well.
///
/// {@template flutter.widgets.platformViews.layout}
/// The widget fills all available space, the parent of this object must provide bounded layout
/// The widget fill all available space, the parent of this object must provide bounded layout
/// constraints.
/// {@endtemplate}
///
/// AndroidView participates in Flutter's [GestureArena]s, and dispatches touch events to the
/// Android view iff it won the arena. Specific gestures that should be dispatched to the Android
...
...
@@ -43,23 +41,19 @@ import 'framework.dart';
/// }
/// ```
///
/// {@template flutter.widgets.platformViews.lifetime}
/// The platform view's lifetime is the same as the lifetime of the [State] object for this widget.
/// The Android view's lifetime is the same as the lifetime of the [State] object for this widget.
/// When the [State] is disposed the platform view (and auxiliary resources) are lazily
/// released (some resources are immediately released and some by platform garbage collector).
/// A stateful widget's state is disposed when the widget is removed from the tree or when it is
/// moved within the tree. If the stateful widget has a key and it's only moved relative to its siblings,
/// or it has a [GlobalKey] and it's moved within the tree, it will not be disposed.
/// {@endtemplate}
class
AndroidView
extends
StatefulWidget
{
/// Creates a widget that embeds an Android view.
///
/// {@template flutter.widgets.platformViews.constructorParams}
/// The `viewType` and `hitTestBehavior` parameters must not be null.
/// {@endtemplate}
/// If `creationParams` is not null then `creationParamsCodec` must not be null.
AndroidView
({
// ignore: prefer_const_constructors_in_immutables
// TODO(aam): Remove lint ignore above once
https://
dartbug.com/34297 is fixed
// TODO(aam): Remove lint ignore above once dartbug.com/34297 is fixed
Key
key
,
@required
this
.
viewType
,
this
.
onPlatformViewCreated
,
...
...
@@ -74,32 +68,25 @@ class AndroidView extends StatefulWidget {
super
(
key:
key
);
/// The unique identifier for Android view type to be embedded by this widget.
///
/// A [PlatformViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html)
/// for this type must have been registered.
///
/// See also: [AndroidView] for an example of registering a platform view factory.
final
String
viewType
;
/// {@template flutter.widgets.platformViews.createdParam}
/// Callback to invoke after the platform view has been created.
/// Callback to invoke after the Android view has been created.
///
/// May be null.
/// {@endtemplate}
final
PlatformViewCreatedCallback
onPlatformViewCreated
;
/// {@template flutter.widgets.platformViews.hittestParam}
/// How this widget should behave during hit testing.
///
/// This defaults to [PlatformViewHitTestBehavior.opaque].
/// {@endtemplate}
final
PlatformViewHitTestBehavior
hitTestBehavior
;
/// {@template flutter.widgets.platformViews.directionParam}
/// The text direction to use for the embedded view.
///
/// If this is null, the ambient [Directionality] is used instead.
/// {@endtemplate}
final
TextDirection
layoutDirection
;
/// Which gestures should be forwarded to the Android view.
...
...
@@ -170,50 +157,7 @@ class AndroidView extends StatefulWidget {
final
MessageCodec
<
dynamic
>
creationParamsCodec
;
@override
State
<
AndroidView
>
createState
()
=>
_AndroidViewState
();
}
// TODO(amirh): describe the embedding mechanism.
/// This is work in progress, not yet ready to be used, and requires a custom engine build. Embeds an iOS view in the Widget hierarchy.
///
/// Embedding iOS views is an expensive operation and should be avoided when a Flutter
/// equivalent is possible.
///
/// {@macro flutter.widgets.platformViews.layout}
///
/// {@macro flutter.widgets.platformViews.lifetime}
class
UiKitView
extends
StatefulWidget
{
/// Creates a widget that embeds an iOS view.
///
/// {@macro flutter.widgets.platformViews.constructorParams}
UiKitView
({
// ignore: prefer_const_constructors_in_immutables
// TODO(aam): Remove lint ignore above once https://dartbug.com/34297 is fixed
Key
key
,
@required
this
.
viewType
,
this
.
onPlatformViewCreated
,
this
.
hitTestBehavior
=
PlatformViewHitTestBehavior
.
opaque
,
this
.
layoutDirection
,
})
:
assert
(
viewType
!=
null
),
assert
(
hitTestBehavior
!=
null
),
super
(
key:
key
);
// TODO(amirh): reference the iOS API doc once avaliable.
/// The unique identifier for iOS view type to be embedded by this widget.
///
/// A PlatformViewFactory for this type must have been registered.
final
String
viewType
;
/// {@macro flutter.widgets.platformViews.createdParam}
final
PlatformViewCreatedCallback
onPlatformViewCreated
;
/// {@macro flutter.widgets.platformViews.hittestParam}
final
PlatformViewHitTestBehavior
hitTestBehavior
;
/// {@macro flutter.widgets.platformViews.directionParam}
final
TextDirection
layoutDirection
;
@override
State
<
UiKitView
>
createState
()
=>
_UiKitViewState
();
State
createState
()
=>
_AndroidViewState
();
}
class
_AndroidViewState
extends
State
<
AndroidView
>
{
...
...
@@ -239,17 +183,19 @@ class _AndroidViewState extends State<AndroidView> {
return
;
}
_initialized
=
true
;
_layoutDirection
=
_findLayoutDirection
();
_createNewAndroidView
();
}
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
_initializeOnce
();
final
TextDirection
newLayoutDirection
=
_findLayoutDirection
();
final
bool
didChangeLayoutDirection
=
_layoutDirection
!=
newLayoutDirection
;
_layoutDirection
=
newLayoutDirection
;
_initializeOnce
();
if
(
didChangeLayoutDirection
)
{
// The native view will update asynchronously, in the meantime we don't want
// to block the framework. (so this is intentionally not awaiting).
...
...
@@ -300,97 +246,6 @@ class _AndroidViewState extends State<AndroidView> {
}
}
class
_UiKitViewState
extends
State
<
UiKitView
>
{
int
_id
;
UiKitViewController
_controller
;
TextDirection
_layoutDirection
;
bool
_initialized
=
false
;
static
final
Set
<
Factory
<
OneSequenceGestureRecognizer
>>
_emptyRecognizersSet
=
Set
<
Factory
<
OneSequenceGestureRecognizer
>>();
@override
Widget
build
(
BuildContext
context
)
{
if
(
_controller
==
null
)
{
return
const
SizedBox
.
expand
();
}
return
_UiKitPlatformView
(
viewId:
_id
,
hitTestBehavior:
widget
.
hitTestBehavior
,
);
}
void
_initializeOnce
()
{
if
(
_initialized
)
{
return
;
}
_initialized
=
true
;
_createNewUiKitView
();
}
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
final
TextDirection
newLayoutDirection
=
_findLayoutDirection
();
final
bool
didChangeLayoutDirection
=
_layoutDirection
!=
newLayoutDirection
;
_layoutDirection
=
newLayoutDirection
;
_initializeOnce
();
if
(
didChangeLayoutDirection
)
{
// The native view will update asynchronously, in the meantime we don't want
// to block the framework. (so this is intentionally not awaiting).
_controller
?.
setLayoutDirection
(
_layoutDirection
);
}
}
@override
void
didUpdateWidget
(
UiKitView
oldWidget
)
{
super
.
didUpdateWidget
(
oldWidget
);
final
TextDirection
newLayoutDirection
=
_findLayoutDirection
();
final
bool
didChangeLayoutDirection
=
_layoutDirection
!=
newLayoutDirection
;
_layoutDirection
=
newLayoutDirection
;
if
(
widget
.
viewType
!=
oldWidget
.
viewType
)
{
_controller
?.
dispose
();
_createNewUiKitView
();
return
;
}
if
(
didChangeLayoutDirection
)
{
_controller
?.
setLayoutDirection
(
_layoutDirection
);
}
}
TextDirection
_findLayoutDirection
()
{
assert
(
widget
.
layoutDirection
!=
null
||
debugCheckHasDirectionality
(
context
));
return
widget
.
layoutDirection
??
Directionality
.
of
(
context
);
}
@override
void
dispose
()
{
_controller
?.
dispose
();
super
.
dispose
();
}
Future
<
void
>
_createNewUiKitView
()
async
{
_id
=
platformViewsRegistry
.
getNextPlatformViewId
();
final
UiKitViewController
controller
=
await
PlatformViewsService
.
initUiKitView
(
id:
_id
,
viewType:
widget
.
viewType
,
layoutDirection:
_layoutDirection
,
);
if
(!
mounted
)
{
controller
.
dispose
();
return
;
}
if
(
widget
.
onPlatformViewCreated
!=
null
)
{
widget
.
onPlatformViewCreated
(
_id
);
}
setState
(()
{
_controller
=
controller
;
});
}
}
class
_AndroidPlatformView
extends
LeafRenderObjectWidget
{
const
_AndroidPlatformView
({
Key
key
,
...
...
@@ -421,30 +276,3 @@ class _AndroidPlatformView extends LeafRenderObjectWidget {
renderObject
.
updateGestureRecognizers
(
gestureRecognizers
);
}
}
class
_UiKitPlatformView
extends
LeafRenderObjectWidget
{
const
_UiKitPlatformView
({
Key
key
,
@required
this
.
viewId
,
@required
this
.
hitTestBehavior
,
})
:
assert
(
viewId
!=
null
),
assert
(
hitTestBehavior
!=
null
),
super
(
key:
key
);
final
int
viewId
;
final
PlatformViewHitTestBehavior
hitTestBehavior
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
return
RenderUiKitView
(
viewId:
viewId
,
hitTestBehavior:
hitTestBehavior
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
RenderUiKitView
renderObject
)
{
renderObject
.
viewId
=
viewId
;
renderObject
.
hitTestBehavior
=
hitTestBehavior
;
}
}
packages/flutter/test/services/fake_platform_views.dart
View file @
b20e7a26
...
...
@@ -6,19 +6,21 @@ import 'dart:async';
import
'dart:typed_data'
;
import
'package:collection/collection.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/services.dart'
;
class
Fake
Android
PlatformViewsController
{
Fake
AndroidPlatformViewsController
(
)
{
class
FakePlatformViewsController
{
Fake
PlatformViewsController
(
this
.
targetPlatform
)
:
assert
(
targetPlatform
!=
null
)
{
SystemChannels
.
platform_views
.
setMockMethodCallHandler
(
_onMethodCall
);
}
final
TargetPlatform
targetPlatform
;
Iterable
<
Fake
Android
PlatformView
>
get
views
=>
_views
.
values
;
final
Map
<
int
,
Fake
AndroidPlatformView
>
_views
=
<
int
,
FakeAndroid
PlatformView
>{};
Iterable
<
FakePlatformView
>
get
views
=>
_views
.
values
;
final
Map
<
int
,
Fake
PlatformView
>
_views
=
<
int
,
Fake
PlatformView
>{};
final
Map
<
int
,
List
<
Fake
AndroidMotionEvent
>>
motionEvents
=
<
int
,
List
<
FakeAndroid
MotionEvent
>>{};
final
Map
<
int
,
List
<
Fake
MotionEvent
>>
motionEvents
=
<
int
,
List
<
Fake
MotionEvent
>>{};
final
Set
<
String
>
_registeredViewTypes
=
Set
<
String
>();
...
...
@@ -31,6 +33,12 @@ class FakeAndroidPlatformViewsController {
}
Future
<
dynamic
>
_onMethodCall
(
MethodCall
call
)
{
if
(
targetPlatform
==
TargetPlatform
.
android
)
return
_onMethodCallAndroid
(
call
);
return
Future
<
dynamic
>.
sync
(()
=>
null
);
}
Future
<
dynamic
>
_onMethodCallAndroid
(
MethodCall
call
)
{
switch
(
call
.
method
)
{
case
'create'
:
return
_create
(
call
);
...
...
@@ -67,7 +75,7 @@ class FakeAndroidPlatformViewsController {
message:
'Trying to create a platform view of unregistered type:
$viewType
'
,
);
_views
[
id
]
=
Fake
Android
PlatformView
(
id
,
viewType
,
Size
(
width
,
height
),
layoutDirection
,
creationParams
);
_views
[
id
]
=
FakePlatformView
(
id
,
viewType
,
Size
(
width
,
height
),
layoutDirection
,
creationParams
);
final
int
textureId
=
_textureCounter
++;
return
Future
<
int
>.
sync
(()
=>
textureId
);
}
...
...
@@ -121,9 +129,9 @@ class FakeAndroidPlatformViewsController {
}
if
(!
motionEvents
.
containsKey
(
id
))
motionEvents
[
id
]
=
<
Fake
Android
MotionEvent
>
[];
motionEvents
[
id
]
=
<
FakeMotionEvent
>
[];
motionEvents
[
id
].
add
(
Fake
Android
MotionEvent
(
action
,
pointerIds
,
pointerOffsets
));
motionEvents
[
id
].
add
(
FakeMotionEvent
(
action
,
pointerIds
,
pointerOffsets
));
return
Future
<
dynamic
>.
sync
(()
=>
null
);
}
...
...
@@ -144,77 +152,9 @@ class FakeAndroidPlatformViewsController {
}
}
class
FakeIosPlatformViewsController
{
FakeIosPlatformViewsController
()
{
SystemChannels
.
platform_views
.
setMockMethodCallHandler
(
_onMethodCall
);
}
Iterable
<
FakeUiKitView
>
get
views
=>
_views
.
values
;
final
Map
<
int
,
FakeUiKitView
>
_views
=
<
int
,
FakeUiKitView
>{};
class
FakePlatformView
{
final
Set
<
String
>
_registeredViewTypes
=
Set
<
String
>();
// When this completer is non null, the 'create' method channel call will be
// delayed until it completes.
Completer
<
void
>
creationDelay
;
void
registerViewType
(
String
viewType
)
{
_registeredViewTypes
.
add
(
viewType
);
}
Future
<
dynamic
>
_onMethodCall
(
MethodCall
call
)
{
switch
(
call
.
method
)
{
case
'create'
:
return
_create
(
call
);
case
'dispose'
:
return
_dispose
(
call
);
}
return
Future
<
dynamic
>.
sync
(()
=>
null
);
}
Future
<
dynamic
>
_create
(
MethodCall
call
)
async
{
if
(
creationDelay
!=
null
)
await
creationDelay
.
future
;
final
Map
<
dynamic
,
dynamic
>
args
=
call
.
arguments
;
final
int
id
=
args
[
'id'
];
final
String
viewType
=
args
[
'viewType'
];
if
(
_views
.
containsKey
(
id
))
{
throw
PlatformException
(
code:
'error'
,
message:
'Trying to create an already created platform view, view id:
$id
'
,
);
}
if
(!
_registeredViewTypes
.
contains
(
viewType
))
{
throw
PlatformException
(
code:
'error'
,
message:
'Trying to create a platform view of unregistered type:
$viewType
'
,
);
}
_views
[
id
]
=
FakeUiKitView
(
id
,
viewType
);
return
Future
<
int
>.
sync
(()
=>
null
);
}
Future
<
dynamic
>
_dispose
(
MethodCall
call
)
{
final
int
id
=
call
.
arguments
;
if
(!
_views
.
containsKey
(
id
))
{
throw
PlatformException
(
code:
'error'
,
message:
'Trying to dispose a platform view with unknown id:
$id
'
,
);
}
_views
.
remove
(
id
);
return
Future
<
dynamic
>.
sync
(()
=>
null
);
}
}
class
FakeAndroidPlatformView
{
FakeAndroidPlatformView
(
this
.
id
,
this
.
type
,
this
.
size
,
this
.
layoutDirection
,
[
this
.
creationParams
]);
FakePlatformView
(
this
.
id
,
this
.
type
,
this
.
size
,
this
.
layoutDirection
,
[
this
.
creationParams
]);
final
int
id
;
final
String
type
;
...
...
@@ -224,9 +164,9 @@ class FakeAndroidPlatformView {
@override
bool
operator
==(
dynamic
other
)
{
if
(
other
.
runtimeType
!=
FakeAndroid
PlatformView
)
if
(
other
is
!
Fake
PlatformView
)
return
false
;
final
Fake
Android
PlatformView
typedOther
=
other
;
final
FakePlatformView
typedOther
=
other
;
return
id
==
typedOther
.
id
&&
type
==
typedOther
.
type
&&
creationParams
==
typedOther
.
creationParams
&&
...
...
@@ -238,12 +178,12 @@ class FakeAndroidPlatformView {
@override
String
toString
()
{
return
'Fake
Android
PlatformView(id:
$id
, type:
$type
, size:
$size
, layoutDirection:
$layoutDirection
, creationParams:
$creationParams
)'
;
return
'FakePlatformView(id:
$id
, type:
$type
, size:
$size
, layoutDirection:
$layoutDirection
, creationParams:
$creationParams
)'
;
}
}
class
Fake
Android
MotionEvent
{
const
Fake
Android
MotionEvent
(
this
.
action
,
this
.
pointerIds
,
this
.
pointers
);
class
FakeMotionEvent
{
const
FakeMotionEvent
(
this
.
action
,
this
.
pointerIds
,
this
.
pointers
);
final
int
action
;
final
List
<
Offset
>
pointers
;
...
...
@@ -252,9 +192,9 @@ class FakeAndroidMotionEvent {
@override
bool
operator
==(
dynamic
other
)
{
if
(
other
is
!
Fake
Android
MotionEvent
)
if
(
other
is
!
FakeMotionEvent
)
return
false
;
final
Fake
Android
MotionEvent
typedOther
=
other
;
final
FakeMotionEvent
typedOther
=
other
;
const
ListEquality
<
Offset
>
offsetsEq
=
ListEquality
<
Offset
>();
const
ListEquality
<
int
>
pointersEq
=
ListEquality
<
int
>();
return
pointersEq
.
equals
(
pointerIds
,
typedOther
.
pointerIds
)
&&
...
...
@@ -267,30 +207,6 @@ class FakeAndroidMotionEvent {
@override
String
toString
()
{
return
'FakeAndroidMotionEvent(action:
$action
, pointerIds:
$pointerIds
, pointers:
$pointers
)'
;
}
}
class
FakeUiKitView
{
FakeUiKitView
(
this
.
id
,
this
.
type
);
final
int
id
;
final
String
type
;
@override
bool
operator
==(
dynamic
other
)
{
if
(
other
.
runtimeType
!=
FakeUiKitView
)
return
false
;
final
FakeUiKitView
typedOther
=
other
;
return
id
==
typedOther
.
id
&&
type
==
typedOther
.
type
;
}
@override
int
get
hashCode
=>
hashValues
(
id
,
type
);
@override
String
toString
()
{
return
'FakeIosPlatformView(id:
$id
, type:
$type
)'
;
return
'FakeMotionEvent(action:
$action
, pointerIds:
$pointerIds
, pointers:
$pointers
)'
;
}
}
packages/flutter/test/services/platform_views_test.dart
View file @
b20e7a26
...
...
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/services.dart'
;
import
'../flutter_test_alternative.dart'
;
...
...
@@ -9,11 +10,11 @@ import '../flutter_test_alternative.dart';
import
'fake_platform_views.dart'
;
void
main
(
)
{
FakePlatformViewsController
viewsController
;
group
(
'Android'
,
()
{
FakeAndroidPlatformViewsController
viewsController
;
setUp
(()
{
viewsController
=
Fake
AndroidPlatformViewsController
(
);
viewsController
=
Fake
PlatformViewsController
(
TargetPlatform
.
android
);
});
test
(
'create Android view of unregistered type'
,
()
async
{
...
...
@@ -37,9 +38,9 @@ void main() {
.
setSize
(
const
Size
(
200.0
,
300.0
));
expect
(
viewsController
.
views
,
unorderedEquals
(<
Fake
Android
PlatformView
>[
Fake
Android
PlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
Fake
Android
PlatformView
(
1
,
'webview'
,
const
Size
(
200.0
,
300.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
),
unorderedEquals
(<
FakePlatformView
>[
FakePlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
FakePlatformView
(
1
,
'webview'
,
const
Size
(
200.0
,
300.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
),
]));
});
...
...
@@ -64,11 +65,11 @@ void main() {
PlatformViewsService
.
initAndroidView
(
id:
1
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
viewController
.
setSize
(
const
Size
(
200.0
,
300.0
));
await
viewController
.
dispose
();
viewController
.
dispose
();
expect
(
viewsController
.
views
,
unorderedEquals
(<
Fake
Android
PlatformView
>[
Fake
Android
PlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
unorderedEquals
(<
FakePlatformView
>[
FakePlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
]));
});
...
...
@@ -93,9 +94,9 @@ void main() {
await
viewController
.
setSize
(
const
Size
(
500.0
,
500.0
));
expect
(
viewsController
.
views
,
unorderedEquals
(<
Fake
Android
PlatformView
>[
Fake
Android
PlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
Fake
Android
PlatformView
(
1
,
'webview'
,
const
Size
(
500.0
,
500.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
unorderedEquals
(<
FakePlatformView
>[
FakePlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
FakePlatformView
(
1
,
'webview'
,
const
Size
(
500.0
,
500.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
]));
});
...
...
@@ -128,8 +129,8 @@ void main() {
await
viewController
.
setSize
(
const
Size
(
100.0
,
100.0
));
expect
(
viewsController
.
views
,
unorderedEquals
(<
Fake
Android
PlatformView
>[
Fake
Android
PlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
unorderedEquals
(<
FakePlatformView
>[
FakePlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
]));
});
...
...
@@ -141,88 +142,9 @@ void main() {
await
viewController
.
setLayoutDirection
(
TextDirection
.
rtl
);
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
FakeAndroidPlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
),
]));
});
});
group
(
'iOS'
,
()
{
FakeIosPlatformViewsController
viewsController
;
setUp
(()
{
viewsController
=
FakeIosPlatformViewsController
();
});
test
(
'create iOS view of unregistered type'
,
()
async
{
expect
(
()
{
return
PlatformViewsService
.
initUiKitView
(
id:
0
,
viewType:
'web'
,
layoutDirection:
TextDirection
.
ltr
,
);
},
throwsA
(
isInstanceOf
<
PlatformException
>()),
);
});
test
(
'create iOS views'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initUiKitView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
PlatformViewsService
.
initUiKitView
(
id:
1
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
rtl
);
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeUiKitView
>[
FakeUiKitView
(
0
,
'webview'
),
FakeUiKitView
(
1
,
'webview'
),
]),
);
});
test
(
'reuse iOS view id'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initUiKitView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
,
);
expect
(
()
=>
PlatformViewsService
.
initUiKitView
(
id:
0
,
viewType:
'web'
,
layoutDirection:
TextDirection
.
ltr
),
throwsA
(
isInstanceOf
<
PlatformException
>()),
);
});
test
(
'dispose iOS view'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initUiKitView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
final
UiKitViewController
viewController
=
await
PlatformViewsService
.
initUiKitView
(
id:
1
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
viewController
.
dispose
();
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeUiKitView
>[
FakeUiKitView
(
0
,
'webview'
),
unorderedEquals
(<
FakePlatformView
>[
FakePlatformView
(
0
,
'webview'
,
const
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
),
]));
});
test
(
'dispose inexisting iOS view'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initUiKitView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
final
UiKitViewController
viewController
=
await
PlatformViewsService
.
initUiKitView
(
id:
1
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
viewController
.
dispose
();
expect
(
()
async
{
await
viewController
.
dispose
();
},
throwsA
(
isInstanceOf
<
PlatformException
>()),
);
});
});
}
packages/flutter/test/widgets/platform_view_test.dart
View file @
b20e7a26
This diff is collapsed.
Click to expand it.
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