使用平台視圖在您的 Flutter 應用程式中託管原生 Android 檢視
平台視圖允許您在 Flutter 應用程式中嵌入原生視圖,因此您可以從 Dart 對原生視圖應用轉換、裁剪和不透明度。
舉例來說,這讓您可以直接在您的 Flutter 應用程式中使用 Android SDK 的原生 Google 地圖。
Android 上的平台視圖有兩種實作方式。它們在效能和保真度方面都有取捨。平台視圖需要 Android API 23 以上版本。
平台視圖會像平常一樣渲染。Flutter 內容會渲染到紋理中。SurfaceFlinger 會合成 Flutter 內容和平台視圖。
+
Android 視圖的最佳效能和保真度。-
Flutter 效能會降低。-
應用程式的 FPS 會較低。-
某些可以應用於 Flutter 小部件的轉換在應用於平台視圖時將無法運作。
平台視圖會渲染到紋理中。Flutter 會繪製平台視圖(透過紋理)。Flutter 內容會直接渲染到 Surface 中。
+
Android 視圖的良好效能+
Flutter 渲染的最佳效能。+
所有轉換都可正確運作。-
快速滾動(例如網頁視圖)會變得不順暢-
SurfaceView 在此模式下會有問題,將會被移動到虛擬顯示器中(破壞 a11y)-
除非 Flutter 渲染到 TextureView 中,否則文字放大鏡將會失效。
若要在 Android 上建立平台視圖,請按照下列步驟操作
在 Dart 端
#在 Dart 端,建立一個 Widget
並新增以下其中一種 build 實作。
混合組合
#例如,在您的 Dart 檔案 native_view_example.dart
中,使用以下指示
新增以下 import
dartimport 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart';
實作
build()
方法dartWidget build(BuildContext context) { // This is used in the platform side to register the view. const String viewType = '<platform-view-type>'; // Pass parameters to the platform side. const Map<String, dynamic> creationParams = <String, dynamic>{}; return PlatformViewLink( viewType: viewType, surfaceFactory: (context, controller) { return AndroidViewSurface( controller: controller as AndroidViewController, gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{}, hitTestBehavior: PlatformViewHitTestBehavior.opaque, ); }, onCreatePlatformView: (params) { return PlatformViewsService.initSurfaceAndroidView( id: params.id, viewType: viewType, layoutDirection: TextDirection.ltr, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), onFocus: () { params.onFocusChanged(true); }, ) ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) ..create(); }, ); }
如需更多資訊,請參閱 API 文件:
TextureLayerHybridComposition
#例如,在您的 Dart 檔案 native_view_example.dart
中,使用以下指示
新增以下 import
dartimport 'package:flutter/material.dart'; import 'package:flutter/services.dart';
實作
build()
方法dartWidget build(BuildContext context) { // This is used in the platform side to register the view. const String viewType = '<platform-view-type>'; // Pass parameters to the platform side. final Map<String, dynamic> creationParams = <String, dynamic>{}; return AndroidView( viewType: viewType, layoutDirection: TextDirection.ltr, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), ); }
如需更多資訊,請參閱 API 文件:
在平台端
#在平台端,在 Kotlin 或 Java 中使用標準的 io.flutter.plugin.platform
套件
在您的原生程式碼中,實作以下內容
擴展 io.flutter.plugin.platform.PlatformView
以提供 android.view.View
的參考(例如,NativeView.kt
)
package dev.flutter.example
import android.content.Context
import android.graphics.Color
import android.view.View
import android.widget.TextView
import io.flutter.plugin.platform.PlatformView
internal class NativeView(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
private val textView: TextView
override fun getView(): View {
return textView
}
override fun dispose() {}
init {
textView = TextView(context)
textView.textSize = 72f
textView.setBackgroundColor(Color.rgb(255, 255, 255))
textView.text = "Rendered on a native Android view (id: $id)"
}
}
建立一個工廠類別,建立先前建立的 NativeView
的實例(例如,NativeViewFactory.kt
)
package dev.flutter.example
import android.content.Context
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory
class NativeViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val creationParams = args as Map<String?, Any?>?
return NativeView(context, viewId, creationParams)
}
}
最後,註冊平台視圖。您可以在應用程式或外掛程式中執行此操作。
對於應用程式註冊,請修改應用程式的主要活動(例如,MainActivity.kt
)
package dev.flutter.example
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine
.platformViewsController
.registry
.registerViewFactory("<platform-view-type>",
NativeViewFactory())
}
}
對於外掛程式註冊,請修改外掛程式的主要類別(例如,PlatformViewPlugin.kt
)
package dev.flutter.plugin.example
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
class PlatformViewPlugin : FlutterPlugin {
override fun onAttachedToEngine(binding: FlutterPluginBinding) {
binding
.platformViewRegistry
.registerViewFactory("<platform-view-type>", NativeViewFactory())
}
override fun onDetachedFromEngine(binding: FlutterPluginBinding) {}
}
在您的原生程式碼中,實作以下內容
擴展 io.flutter.plugin.platform.PlatformView
以提供 android.view.View
的參考(例如,NativeView.java
)
package dev.flutter.example;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.platform.PlatformView;
import java.util.Map;
class NativeView implements PlatformView {
@NonNull private final TextView textView;
NativeView(@NonNull Context context, int id, @Nullable Map<String, Object> creationParams) {
textView = new TextView(context);
textView.setTextSize(72);
textView.setBackgroundColor(Color.rgb(255, 255, 255));
textView.setText("Rendered on a native Android view (id: " + id + ")");
}
@NonNull
@Override
public View getView() {
return textView;
}
@Override
public void dispose() {}
}
建立一個工廠類別,建立先前建立的 NativeView
的實例(例如,NativeViewFactory.java
)
package dev.flutter.example;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;
class NativeViewFactory extends PlatformViewFactory {
NativeViewFactory() {
super(StandardMessageCodec.INSTANCE);
}
@NonNull
@Override
public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
final Map<String, Object> creationParams = (Map<String, Object>) args;
return new NativeView(context, id, creationParams);
}
}
最後,註冊平台視圖。您可以在應用程式或外掛程式中執行此操作。
對於應用程式註冊,請修改應用程式的主要活動(例如,MainActivity.java
)
package dev.flutter.example;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
flutterEngine
.getPlatformViewsController()
.getRegistry()
.registerViewFactory("<platform-view-type>", new NativeViewFactory());
}
}
對於外掛程式註冊,請修改外掛程式的主要檔案(例如,PlatformViewPlugin.java
)
package dev.flutter.plugin.example;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
public class PlatformViewPlugin implements FlutterPlugin {
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
binding
.getPlatformViewRegistry()
.registerViewFactory("<platform-view-type>", new NativeViewFactory());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}
}
如需更多資訊,請參閱 API 文件:
最後,修改您的 build.gradle
檔案,以要求最低的 Android SDK 版本之一
android {
defaultConfig {
minSdk = 19 // if using hybrid composition
minSdk = 20 // if using virtual display.
}
}
Surface View
#處理 SurfaceView 對於 Flutter 來說是有問題的,應盡可能避免。
手動檢視失效
#某些 Android 視圖在內容變更時不會自行失效。一些範例視圖包括 SurfaceView
和 SurfaceTexture
。當您的平台視圖包含這些視圖時,您需要在繪製它們之後(或更具體地說:在交換鏈翻轉之後)手動使視圖失效。手動視圖失效是透過在視圖或其父視圖之一上呼叫 invalidate
來完成的。
問題
#效能
#Flutter 中的平台視圖會帶來效能上的取捨。
例如,在典型的 Flutter 應用程式中,Flutter UI 是在專用的 raster 執行緒上合成的。這讓 Flutter 應用程式速度很快,因為主平台執行緒很少被阻塞。
當使用混合合成渲染平台視圖時,Flutter UI 是從平台執行緒合成的,這會與處理 OS 或外掛程式訊息等其他任務競爭。
在 Android 10 之前,混合合成會將每個 Flutter 影格從圖形記憶體複製到主記憶體,然後再複製回 GPU 紋理。由於此複製是每個影格發生的,因此整個 Flutter UI 的效能可能會受到影響。在 Android 10 或更高版本中,圖形記憶體只會複製一次。
另一方面,虛擬顯示器會讓原生視圖的每個像素流經額外的中間圖形緩衝區,這會消耗圖形記憶體並降低繪圖效能。
對於複雜的情況,有一些技術可以用來緩解這些問題。
例如,您可以在 Dart 中進行動畫時使用佔位符紋理。換句話說,如果平台視圖渲染時動畫很慢,請考慮拍攝原生視圖的螢幕擷取畫面並將其渲染為紋理。
如需更多資訊,請參閱
除非另有說明,否則本網站上的文件反映 Flutter 的最新穩定版本。頁面最後更新於 2024-10-24。 檢視來源 或 回報問題。