Flutter 混合開發系列 包含如下:
- 嵌入原生View-Android
- 嵌入原生View-iOS
- 與原生通信-MethodChannel
- 與原生通信-BasicMessageChannel
- 與原生通信-EventChannel
- 添加 Flutter 到 Android Activity
- 添加 Flutter 到 Android Fragment
- 添加 Flutter 到 iOS
每個工作日分享一篇,歡迎關注、點贊及轉發。
使用新引擎創建 FlutterFragment
添加 Flutter 到 Fragment 與添加 Activity 基本一樣,如果添加到 Activity 滿足需求,建議使用 Activity,因為 Activity 更加靈活和易於使用。
添加到 Fragment 代碼:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragment = FlutterFragment.createDefault()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit()
}
}
activity_main 布局文件修改如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@+id/button"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="跳轉"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
紅色區域就是 FlutterFragment 部分,這里大部分是 Android 原生的知識。
上面已經加載了 UI,但並不能一些交互和行為,通常情況下,需要將 Activity 的生命周期透傳給 FlutterFragment:
class MainActivity : AppCompatActivity() {
override fun onPostResume() {
super.onPostResume()
flutterFragment!!.onPostResume()
}
override fun onNewIntent(@NonNull intent: Intent) {
flutterFragment!!.onNewIntent(intent)
}
override fun onBackPressed() {
flutterFragment!!.onBackPressed()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
flutterFragment!!.onRequestPermissionsResult(
requestCode,
permissions,
grantResults
)
}
override fun onUserLeaveHint() {
flutterFragment!!.onUserLeaveHint()
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
flutterFragment!!.onTrimMemory(level)
}
}
初始化新引擎路由
指定引擎路由:
val fragment = FlutterFragment
.withNewEngine()
.initialRoute("one_page")
.build<FlutterFragment>()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit()
使用緩存引擎創建 FlutterFragment
上面的方式每一個 FlutterFragment 都會創建一個 FlutterEngine(Flutter 引擎),當然 FlutterFragment 也支持 緩存引擎,用法與 Activity 一樣,在 MyApplication 啟動引擎:
class MyApplication : Application() {
lateinit var flutterEngine: FlutterEngine
override fun onCreate() {
super.onCreate()
flutterEngine = FlutterEngine(this)
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
.getInstance()
.put("engine_id", flutterEngine)
}
}
使用:
val fragment = FlutterFragment
.withCachedEngine("engine_id")
.build<FlutterFragment>()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit()
初始化緩存引擎路由
初始化緩存引擎的路由:
flutterEngine = FlutterEngine(this)
flutterEngine.navigationChannel.setInitialRoute("one_page")
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
.getInstance()
.put("engine_id", flutterEngine)
更改入門點
默認情況下,FlutterFragment 的 entrypoint(入口點)是 main() 函數,我們可以修改其 entrypoint,
val fragment = FlutterFragment
.withNewEngine()
.dartEntrypoint("newMain")
.build<FlutterFragment>()
在 main.dart 文件中添加 entrypoint(入口點):
void main() => runApp(MyApp());
void newMain()=> runApp(NewApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
'one_page':(context){
return OnePage();
},
'two_page':(context){
return TwoPage();
}
},
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class NewApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TwoPage()
);
}
}
newMain 即新的 entrypoint。
更改 FlutterFragment 的渲染模式
FlutterFragment 的渲染模式有兩種:SurfaceView 和 TextureView,默認是 SurfaceView,SurfaceView 的性能比 TextureView 好,但其層次結構必須在最頂層或最底層,而且在 Android N之前的Android版本上,無法對 SurfaceView 進行動畫處理,因為它們的布局和渲染與其他 View 層次結構不同步,因此要合理選擇渲染模式,渲染模式設置方法如下:
val fragment = FlutterFragment
.withNewEngine()
.renderMode(RenderMode.texture)
.build<FlutterFragment>()
設置 FlutterFragment 透明
默認情況下,FlutterFragment 使用 SurfaceView 渲染不透明背景。對於Flutter未繪制的任何像素,背景均為黑色。由於性能原因,首選使用不透明背景進行渲染。 Android上具有透明的 Flutter 渲染會對性能產生負面影響。但是,有的時候需要其透明,顯示其底下的 UI,因此,Flutter在 FlutterFragment 中支持設置為透明。
val fragment = FlutterFragment
.withNewEngine()
.transparencyMode(TransparencyMode.transparent)
.build<FlutterFragment>()
將按下放置在 FlutterFragment 的底下,
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="跳轉"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
此時 FlutterFragment 的背景已經透明了,但運行時發現並沒有透明,按鈕也沒有顯示,這是因為 Flutter 本身沒有設置透明,設置Flutter 透明:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
backgroundColor: Colors.transparent,
...
);
}
交流
老孟Flutter博客(330個控件用法+實戰入門系列文章):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:
![]() |
![]() |