扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
In gradle-wapper.property:
创新互联是一家专注于成都网站建设、成都做网站与策划设计,孝昌网站建设哪家好?创新互联做网站,专注于网站建设十年,网设计领域的专业建站公司;建站业务涵盖:孝昌等地区。孝昌做网站价格咨询:18982081108
" distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip"
in build.gradle:
dependencies{
classpath'com.android.tools.build:gradle:7.2.1'
classpath"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
参照:;authuser=0#updating-gradle
四大组件中添加 android:exported="true"
如果我们目前的项目是Android的,但是接下来我们希望部分页面可以使用Flutter进行开发,甚至我们希望在Native页面中嵌入FlutterUI组件,那么我们该如何实现呢?
假设你现在Android项目的目录的结构是这样的
这时候如果你想创建一个Flutter模块,使得Android模块和Flutter模块之间可以进行交互,我们可以通过Android Studio新建一个Flutter Module,具体过程是:File — New — New Module ,之后选择Flutter Module,指定Project Location的路径为
也就是说,最终你的项目结构会是这样的
接下来在Android Module的 build.gradle 文件中添加flutter依赖
先创建一个Flutter页面
这里比较重要的是 window.defaultRouteName 这个字段,这个字段可以接收从Native传递过来的参数 (下文我们会介绍原生传递参数的方法),也就是说通过这个字段我们就可以进行Flutter页面的路由的分发
我们可以直接在Android的 MainActivity 中启动一个 FlutterActivity ,这里的 initialRoute 方法中传递的参数就对应Flutter层的 window.defaultRouteName
注意:需要在 AndroidManifest.xml 注册 FlutterActivity
自己创建一个 FlutterAppActivity 继承自 FlutterActivity
在 MainActivity 中启动 FlutterAppActivity (另外别忘了在 AndroidManifest.xml 中注册 FlutterAppActivity )
两种启动方式的区别
如果单纯只是想打开一个Flutter页面,两种方式实际上基本没有太大区别,第一种方式也许还会更简单一点。但是,在Flutter开发中,我们往往还需要开发一些Native插件供Flutter调用,如果使用复写 FlutterActivity 的方式更有利于我们在 FlutterActivity 中注册我们的Native插件,所以实际开发中一般推荐使用第二种方式
扩展思考
initialRoute 从名称上看起来是Flutter提供给我们进行Native与Flutter交互的路由跳转的,但是实际上他就是一个字符串,我们不仅仅可以传递一个路由名称,有时候我们也可以通过这个参数传递一串JSON数据,然后在Flutter端进行解析,这样我们就可以通过这个参数做更多的事情
activity_main.xml
FrameLayout 用于承载Flutter组件
MainActivity.java
使用 FragmentManager 将 FlutterFragment 添加到 FrameLayout 容器中
运行结果
上半部分是原生的TextView,下半部分是Flutter的Text组件
本节主要介绍了Native和Flutter之间的页面跳转,以及同一个页面中Native与Flutter组件的组合。接下来会介绍如何编写Android插件与Flutter进行数据交互
1、界面搭建过程中各种大小单位
Android:通常采用dp设置View宽高(和px像素的换算关系是dp值 × density逻辑密度),sp设置字体大小(会随着系统字体设置的大小而改变)。
Flutter:没有具体的大小单位描述, 和尺寸相关的MediaQueryData类中较为重要的几个值如下:
(一)devicePixelRatio(设备像素比),对应Android中的density
(二)size.width和height,设备的逻辑像素宽高,并非绝对物理像素(例如iphone6的设备像素比是2,通过size获取到的逻辑像素宽高为375 × 667,实际物理像素则为750 × 1334,即分辨率)
(三)textScaleFactor:单位逻辑像素字体像素数,默认为1,设置成1.5则字体变大50%,如果想让Text组件的字体大小不随系统设置的变化而变化,需将这个值设定成固定值1
UI适配解决方案:
1、采用ScreenUtil插件,初始化时候传入设计稿大小,当发现一屏显示的大小有差异时候采用插件提供的setWidth和setHeight来设置具体的宽高(会根据设计稿大小和实际设备逻辑像素宽高比进行缩放)。
2、TextButton、Text等按钮和文本组件,通过设置字体大小和内边距来控制整体的宽高,而非固定其宽高。
2、本地资源文件的引用方式
Android:图片通常存放在res/mipmap或res/drawable下,不同分辨率对应不同后缀名,如mipmap-hdpi、mipmap-xhdpi
Flutter:需在pubspec.yaml中配置,如下图所示
如果只配置父级目录例如(assets/images/common_status)则无法再存放不同尺寸的图片。不同尺寸的图片需建立对应的2.0x、3.0x目录后存放,设备在读取时候会自行根据分辨率去找对应的图片,弊端是每有一张图片就需在pubspec.yaml文件中声明这些图片
1、常用布局的对比
使用下来其他组件大致还算方便,但是相对布局而言使用便利程度上Android原生完胜,ConstraintLayout内部的所有子View可以设置互相之间的位置依赖关系。
而Flutter的Stack组件内部的Children只能通过外层包裹 Align后 固定位置,比如 Alignment.topLeft、Alignment.bottomRight 等。遇到复杂的堆叠布局需要通过外层包裹 Positioned 组件后设置固定的 top 和 left 距离以达到效果,内部子组件之间无法设置位置关联关系。
2、一些常用属性设置上的差异:
Margin外边距
Android:直接在布局文件对View设置android:layout_marginStart、android:layout_marginTop
Flutter:需嵌套 Container 组件并在内部设置具体的 margin 值
Padding内边距
Android:TextView、ImageView、各种Layout都可以直接在属性上设置android:paddingStart
Flutter:需嵌套 Padding 组件并在内部设置具体的值
组件的可见性
Android:每个view都可以通过setVisibility来设置可见、隐藏或者隐藏但占位
Flutter:没有单独设置组件是否显示的api,只能通过 bool 值控制是否添加该组件
事件监听
Android:常规的setOnClickListener和setOnLongClickListener设置单击和长按事件
Flutter:在需要添加事件监听的组件外层嵌套 InkWell 或 GestureDetector 并设置 onTap 等
3、生命周期
Android:
Activity和Fragment各自有完整的生命周期链路onCreate、onStart、onResume、onPause、onDestroy等
Flutter:
万物皆组件,组件继承 WidgetsBindingObserver 并重写 didChangeAppLifecycleState 函数进行监听
退回桌面依次执行inactive 》= paused,此时界面不可见用户不可操作,从桌面重新进入app执行resumed,状态较少如需在某些条件下触发特定操作可能要找别的方案,比如发通知之类的
Flutter--Error: Cannot run with sound null safety, because the following dependencies don't support null safety
flutter sdk提示不是支持 null safety模式
解决方法
1:
在Android Studio中
Run -- Edit Configurations -- Add Additional Run args -- --no-sound-null-safety
2:
flutter run --no-sound-null-safety
flutter build apk --no-sound-null-safety
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流