【Flutter 混合开发】添加 Flutter 到 Android Fragment

Flutter 混合开发系列 包含以下:android

  • 嵌入原生View-Android
  • 嵌入原生View-iOS
  • 与原生通讯-MethodChannel
  • 与原生通讯-BasicMessageChannel
  • 与原生通讯-EventChannel
  • 添加 Flutter 到 Android Activity
  • 添加 Flutter 到 Android Fragment
  • 添加 Flutter 到 iOS

每一个工做日分享一篇,欢迎关注、点赞及转发。git

使用新引擎建立 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 布局文件修改以下:app

<?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 原生的知识。less

上面已经加载了 UI,但并不能一些交互和行为,一般状况下,须要将 Activity 的生命周期透传给 FlutterFragment:ide

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】:

相关文章
相关标签/搜索