1,创建PlatformView
PlatformView是flutter中可以渲染原生界面的view,在android中的体现是AndroidView
flutter 创建AndroidView的时候,实际渲染的是_AndroidViewState build方法
_AndroidViewState
@override
Widget build(BuildContext context) {
return Focus(
focusNode: _focusNode,
onFocusChange: _onFocusChange,
child: _AndroidPlatformView(
controller: _controller,
hitTestBehavior: widget.hitTestBehavior,
gestureRecognizers: widget.gestureRecognizers ?? _emptyRecognizersSet,
),
);
}
_initializeOnce是在didChangeDependencies和didUpdateWidget的时候调用的而且除非viewtype改变了否则只会调用一次
_AndroidViewState
void _initializeOnce() {
if (_initialized) {
return;
}
_initialized = true;
_createNewAndroidView();
_focusNode = FocusNode(debugLabel: 'AndroidView(id: $_id)');
}
_AndroidViewState
void _createNewAndroidView() {
_id = platformViewsRegistry.getNextPlatformViewId();
_controller = PlatformViewsService.initAndroidView(
id: _id,
viewType: widget.viewType,
layoutDirection: _layoutDirection,
creationParams: widget.creationParams,
creationParamsCodec: widget.creationParamsCodec,
onFocus: () {
_focusNode.requestFocus();
},
);
if (widget.onPlatformViewCreated != null) {
_controller.addOnPlatformViewCreatedListener(widget.onPlatformViewCreated);
}
}
关注 PlatformViewsService.initAndroidView ,内部创建了一个AndroidViewController,后面创建Texture就是使用这个类创建的
static AndroidViewController initAndroidView({
@required int id,
@required String viewType,
@required TextDirection layoutDirection,
dynamic creationParams,
MessageCodec<dynamic> creationParamsCodec,
VoidCallback onFocus,
}) {
assert(id != null);
assert(viewType != null);
assert(layoutDirection != null);
assert(creationParams == null || creationParamsCodec != null);
final AndroidViewController controller = AndroidViewController._(
id,
viewType,
creationParams,
creationParamsCodec,
layoutDirection,
);
_instance._focusCallbacks[id] = onFocus ?? () {};
return controller;
}
视线转移到AndroidView的Render
RenderAndroidView
void performResize() {
size = constraints.biggest;
_sizePlatformView();
}
Future<void> _sizePlatformView() async {
···
do {
targetSize = size;
await _viewController.setSize(targetSize);
_currentAndroidViewSize = targetSize;
// We've resized the platform view to targetSize, but it is possible that
// while we were resizing the render object's size was changed again.
// In that case we will resize the platform view again.
} while (size != targetSize);
...
}
Future<void> setSize(Size size) async {
if (_state == _AndroidViewState.waitingForSize)
return _create(size);
await SystemChannels.platform_views.invokeMethod<void>('resize', <String, dynamic>{
'id': id,
'width': size.width,
'height': size.height,
});
}
当AndroidViewState为waitingForSize时会调用_create方法
Future<void> _create(Size size) async {
···
_textureId = await SystemChannels.platform_views.invokeMethod('create', args);
_state = _AndroidViewState.created;
for (final PlatformViewCreatedCallback callback in _platformViewCreatedCallbacks) {
callback(id);
}
···
}
此处会调用methodchannel event 为 create返回textureid
继续看android实现
PlatfromViewsChannel.java
private void create(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
Map<String, Object> createArgs = call.arguments();
PlatformViewCreationRequest request =
new PlatformViewCreationRequest(
(int) createArgs.get("id"),
(String) createArgs.get("viewType"),
(double) createArgs.get("width"),
(double) createArgs.get("height"),
(int) createArgs.get("direction"),
createArgs.containsKey("params")
? ByteBuffer.wrap((byte[]) createArgs.get("params"))
: null);
try {
long textureId = handler.createPlatformView(request);
result.success(textureId);
} catch (IllegalStateException exception) {
result.error("error", detailedExceptionString(exception), null);
}
}
public long createPlatformView(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
PlatformViewFactory viewFactory = registry.getFactory(request.viewType);
if (viewFactory == null) {
throw new IllegalStateException(
"Trying to create a platform view of unregistered type: " + request.viewType);
}
Object createParams = null;
if (request.params != null) {
createParams = viewFactory.getCreateArgsCodec().decodeMessage(request.params);
}
int physicalWidth = toPhysicalPixels(request.logicalWidth);
int physicalHeight = toPhysicalPixels(request.logicalHeight);
validateVirtualDisplayDimensions(physicalWidth, physicalHeight);
TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
VirtualDisplayController vdController =
VirtualDisplayController.create(
context,
accessibilityEventsDelegate,
viewFactory,
textureEntry,
physicalWidth,
physicalHeight,
request.viewId,
createParams,
(view, hasFocus) -> {
if (hasFocus) {
platformViewsChannel.invokeViewFocused(request.viewId);
}
});
if (flutterView != null) {
vdController.onFlutterViewAttached(flutterView);
}
vdControllers.put(request.viewId, vdController);
View platformView = vdController.getView();
platformView.setLayoutDirection(request.direction);
return textureEntry.id();
}
上图列出关键步骤,textureRegistry创建了一个SurfaceTextureEntry 这就是flutter最终渲染的texture
@Override
public void resizePlatformView(
@NonNull PlatformViewsChannel.PlatformViewResizeRequest request,
@NonNull Runnable onComplete) {
ensureValidAndroidVersion();
final VirtualDisplayController vdController = vdControllers.get(request.viewId);
if (vdController == null) {
throw new IllegalStateException(
"Trying to resize a platform view with unknown id: " + request.viewId);
}
int physicalWidth = toPhysicalPixels(request.newLogicalWidth);
int physicalHeight = toPhysicalPixels(request.newLogicalHeight);
validateVirtualDisplayDimensions(physicalWidth, physicalHeight);
lockInputConnection(vdController);
vdController.resize(
physicalWidth,
physicalHeight,
new Runnable() {
@Override
public void run() {
unlockInputConnection(vdController);
onComplete.run();
}
});
}
VirtualDisplayController 是控制展示的类
public static VirtualDisplayController create(
Context context,
AccessibilityEventsDelegate accessibilityEventsDelegate,
PlatformViewFactory viewFactory,
TextureRegistry.SurfaceTextureEntry textureEntry,
int width,
int height,
int viewId,
Object createParams,
OnFocusChangeListener focusChangeListener) {
textureEntry.surfaceTexture().setDefaultBufferSize(width, height);
Surface surface = new Surface(textureEntry.surfaceTexture());
DisplayManager displayManager =
(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
int densityDpi = context.getResources().getDisplayMetrics().densityDpi;
VirtualDisplay virtualDisplay =
displayManager.createVirtualDisplay("flutter-vd", width, height, densityDpi, surface, 0);
if (virtualDisplay == null) {
return null;
}
return new VirtualDisplayController(
context,
accessibilityEventsDelegate,
virtualDisplay,
viewFactory,
surface,
textureEntry,
focusChangeListener,
viewId,
createParams);
}
virturalDisplay需要渲染的显示抽象
create方法创建了VirtualDisplay,他负责渲染图像到Flutter提供的surface。
我们关注SingleViewPresentation
onCreate(){ 创建view,在attacEngine的时候调用
···
if (state.platformView == null) {
state.platformView = viewFactory.create(context, viewId, createParams);
}
···
}
然后每次factory创建的自定义view调用onDraw方法就会渲染到flutter提供的surface中,达到在flutter中渲染的目的
AndroidView事件分发
获取到手指事件
MotionEventDispatcher.dart
void handlePointerEvent(PointerEvent event) {
if (event is PointerDownEvent) {
if (nextPointerId == 0)
downTimeMillis = event.timeStamp.inMilliseconds;
pointerProperties[event.pointer] = propertiesFor(event, nextPointerId++);
}
pointerPositions[event.pointer] = coordsFor(event);
dispatchPointerEvent(event);
···
}
分发事件,最终调用了 touch channel回调原生
_MotionEventsDispatcher.dart
void dispatchPointerEvent(PointerEvent event) {
····
final AndroidMotionEvent androidMotionEvent = AndroidMotionEvent(
downTime: downTimeMillis,
eventTime: event.timeStamp.inMilliseconds,
action: action,
pointerCount: pointerPositions.length,
pointerProperties: pointers.map<AndroidPointerProperties>((int i) => pointerProperties[i]).toList(),
pointerCoords: pointers.map<AndroidPointerCoords>((int i) => pointerPositions[i]).toList(),
metaState: 0,
buttonState: 0,
xPrecision: 1.0,
yPrecision: 1.0,
deviceId: 0,
edgeFlags: 0,
source: 0,
flags: 0,
);
viewController.sendMotionEvent(androidMotionEvent);
····
}
AndroidViewController.dart
Future<void> sendMotionEvent(AndroidMotionEvent event) async {
await SystemChannels.platform_views.invokeMethod<dynamic>(
'touch',
event._asList(id),
);
}
android原生代码接受channel事件处理
PlatformViewsController
@Override
public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
ensureValidAndroidVersion();
float density = context.getResources().getDisplayMetrics().density;
PointerProperties[] pointerProperties =
parsePointerPropertiesList(touch.rawPointerPropertiesList)
.toArray(new PointerProperties[touch.pointerCount]);
PointerCoords[] pointerCoords =
parsePointerCoordsList(touch.rawPointerCoords, density)
.toArray(new PointerCoords[touch.pointerCount]);
if (!vdControllers.containsKey(touch.viewId)) {
throw new IllegalStateException(
"Sending touch to an unknown view with id: " + touch.viewId);
}
View view = vdControllers.get(touch.viewId).getView();
MotionEvent event =
MotionEvent.obtain(
touch.downTime.longValue(),
touch.eventTime.longValue(),
touch.action,
touch.pointerCount,
pointerProperties,
pointerCoords,
touch.metaState,
touch.buttonState,
touch.xPrecision,
touch.yPrecision,
touch.deviceId,
touch.edgeFlags,
touch.source,
touch.flags);
view.dispatchTouchEvent(event);
}