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

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】:
![]() |
![]() |
【Flutter 混合开发】添加 Flutter 到 Android Fragment的更多相关文章
- 【Flutter 混合开发】添加 Flutter 到 Android Activity
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- Flutter混合开发:Android接入Flutter
Flutter Google推出已经已经一年多了,单个 Flutter 项目的开发流程已经很成熟了.对与个人开发者来说使用 Flutter 开发一个跨平台的App挺有意思.但是对于现有的项目改造来说还 ...
- 【Flutter 混合开发】添加 Flutter 到 iOS
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- 【Flutter 混合开发】嵌入原生View-Android
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-IOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- 【Flutter 混合开发】嵌入原生View-iOS
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- 【Flutter 混合开发】与原生通信-MethodChannel
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- 【Flutter 混合开发】与原生通信-BasicMessageChannel
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- 【Flutter 混合开发】与原生通信-EventChannel
Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...
- flutter 混合开发
flutter 混合开发 https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps https://flutter.de ...
随机推荐
- 微服务实战系列(四)-注册中心springcloud alibaba nacos
1.场景描述 因要用到微服务,关于注册中心这块,与同事在技术原型上做了讨论,初步定的方案是使用:阿里巴巴的nacos+springcloud gateway,下面表格是同事整理的注册中心对比,以前用的 ...
- phpStudy8.1.0.1配置子域名多网站
版本 这里phpStudy版本为8.1.0.1: 步骤 假设域名为:domain.com:公网IP地址为:42.33.33.33 首先云解析中配置,添加子域名A记录直接指向你的公网IP: ep.dom ...
- 面试可能遇到的关联式容器(map、set等)相关问题
>>>. map与set的区别是什么,各有哪些优势? map中存储的数据是以键值对(key - value)形式并且通过排序(比较key,默认以 '<' 方式排序)存在的( ...
- spring cloud consul 服务治理
对照系统安装响应consul文件(以window为例) 解压文件之后配置环境,进入Path添加文件所在目录, 测试:在文件所在目录下进入指令操作 输入 consul agent -dev 启动成功,在 ...
- Java 实现常见内排序
一.内排序 1.排序基本概念 (1)什么是排序? 排序指将一个数据元素集合或者序列 按照某种规则 重新排列成一个 有序的集合或者序列.分为内排序.外排序.排序算法的好坏直接影响程序的执行速度以及存储空 ...
- Python-TypeError: object() takes no parameters
Error: TypeError: object() takes no parameters Where? 使用自定义类的时候,实例类的时候传递参数,提示这个错误 Why? 因为类实例的时候,并不需要 ...
- 小白也能看懂的ArrayList的扩容机制
来,话不多说进入正题!我们下面用最简单的代码创建ArrayList并添加11个元素,并 一 一 讲解底层源码:在说之前,给大家先普及一些小知识: >ArrayList底层是用数组来实现的 > ...
- 一种基于均值不等式的Listwise损失函数
一种基于均值不等式的Listwise损失函数 1 前言 1.1 Learning to Rank 简介 Learning to Rank (LTR) , 也被叫做排序学习, 是搜索中的重要技术, 其目 ...
- Java高级特性1_流库_初体验
Java高级特性流库_初体验 面对结果编程 在编程里, 有两种编程方式, 一种是面对过程编程, 一种是面对结果编程. 两者区别如下 面向过程编程 面向过程编程需要编程程序让程序依次执行得到自己想要的结 ...
- JVM内存布局(又叫Java运行时数据区)
JVM 堆中的数据是共享的,是占用内存最大的一块区域. 可以执行字节码的模块叫作执行引擎. 执行引擎在线程切换时怎么恢复?依靠的就是程序计数器. JVM 的内存划分与多线程是息息相关的.像我们程序中运 ...

