Flutter 混合开发系列 包含如下:
与原生通信-BasicMessageChannel
添加 Flutter 到 Android Activity
添加 Flutter 到 Android Fragment
每个工作日分享一篇,欢迎关注、点赞及转发。
使用新引擎创建 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, ... ); }