前言
前面两篇文章讲解了在 Flutter 中使用 Canvas 分别实现了 精美表盘 和 微信红包 效果,本篇将继续带领你使用 Canvas 实现简笔的小白兔效果,使用的核心技术为二次贝塞尔曲线和三次贝塞尔曲线的运用。
按照惯例,先看一下最终实现的效果:
Flutter 开发中,Json 数据解析一直是一个痛点,特别是对于从 iOS、Android 或者 Java 转过来的开发者来说尤为明显,在上述平台上开发者习惯了将 Json 数据解析为对象实体然后进行使用,而在 Flutter 上要做到这一步则相对比较麻烦。
Flutter 使用的是 Dart 语言进行开发,而 Dart 语言没有反射,所以无法像 Java 一样通过反射直接将 Json 数据映射为对应的对象实体类对象。官方解决方案是将 Json 数据转换为字典,然后从字典中进行取数使用。但直接从字典中取数很不方便,写代码时没有自动提示很不友好,而且可能在写的时候写错字段名。
基于 Flutter 现状,方便开发时的调用,可以将 Json 转换为字典后再手动映射到对象实体字段里,这样使用时就可以直接使用对应实体类对象,但是这种方法会导致开发过程中写很多冗余代码,因为每一个类都要手动去写对应的映射代码,严重影响开发效率。于是就有了很多将 Json 映射为对象实体类代码的自动生成方案,比如 Json2Dart、JsonToDart、Json To Dart Class 、FlutterJsonBeanFactory 等插件以及 json_to_model 之类的第三方库。其本质原理就是将需要开发者手动编写的映射代码改为自动生成。
笔者经过不断的尝试、实验,发现这些方案或多或少都存在着一些美中不足,经过不断权衡比较再结合实际开发中的使用情况,最后选择了使用 FlutterJsonBeanFactory
插件再加上一些自定义的代码修改,最终达到在项目中快速使用的效果。
接下来本文将主要讲解怎么使用 FlutterJsonBeanFactory
插件结合自定义代码修改,快速实现 Json 解析。
因移动设备的多样性,特别是 Android 的碎片化严重,存在各种各样的分辨率,而 Flutter 跨平台开发又需同时支持 Android 和 iOS ,为尽可能的还原设计图效果提升用户体验,屏幕适配就势在必行了。
Flutter 暂时没有官方的屏幕适配方案,在 Flutter 项目开发中目前大部分的适配方案都是通过比例来进行适配,是一个通用的适配方法,该适配方法也在前端、Android、iOS、小程序等开发中广泛使用。
UI 设计的时候一般会按照一个固定的尺寸进行设计,如 360 x 690
,实际设备分辨率可能是 Google Pixel: 1080 x 1920
、Google Pixel XL: 1440 x 2560
、iPhone 12 Pro Max: 1284 x 2778
等等。开发时如果直接按照设计图写死数值则会出现最后实现的效果跟设计效果不一致的情况。这个时候就可以用比例的方式来进行适配。
将设计图分为固定单位并给这个单位定义一个标识,例如就叫 w
,然后通过获取设备分辨率,使用设备真实宽度除以设计图宽度 ,就得到了 1w
代表的真实宽度:
1w = 设备真实宽度 / 设计图宽度
如设计图尺寸是 360 x 690
,则宽度为 360w
,真实设备宽度为 1080 则 1w = 1080 / 360 = 3
。
根据上面的算法,得到对应设备的 1w
的真实宽度:
Google Pixel: 1w = 1080 / 360 = 3
Google Pixel XL: 1w = 1440 / 360 = 4
iPhone 12 Pro Max: 1w = 1284 / 360 = 3.57
按照同样的算法,可以给高度定义一个单位为 h
, 得出对应设备的高度单位的真实值,如下:
Google Pixel: 1h = 1920 / 690 = 2.78
Google Pixel XL: 1h = 2560 / 690 = 3.71
iPhone 12 Pro Max: 1h = 2778 / 690 = 4.03
得到换算以后 w
、h
的真实值以后,开发过程中就可以使用其来设置 UI 控件的高、宽、间距等,使其最终呈现的效果无限接近设计图的效果。
开发过程中一般采用宽度来进行适配,控件高度要么自适应,要么也设置宽度的单位,然后整体高度根据内容自适应。但是如果有特殊需求也可以使用高度来进行适配,比如需求要求是 banner 占屏幕的 1/4 ,或者要求内容刚好一屏显示,这个时候设置控件的高度时就可以采用高度单位来进行适配。
基于上面的算法,在项目中就可以实现对应的适配方案了,但本着不重复造轮子的思想,项目开发中可以直接使用 flutter_screenutil 这个适配库。
在 Flutter 应用开发过程中,状态管理、路由管理在应用框架中扮演着重要角色。目前主流的解决方案有 Google 官方的 Provider,三方的 GetX、Bloc、 fish-redux 等。经过多方实践对比,GetX 脱颖而出。
GetX 是一个轻量且强大的解决方案,拥有高性能的状态管理、智能的依赖注入以及便捷的路由管理。
本文将从零开始手把手教你如何集成 GetX 搭建属于你的 Flutter 应用框架。
在 pubspec.yaml
文件中添加 GetX 的依赖,如下:
1 | dependencies: |
要使用 GetX 需要对 GetX 进行初始化,将默认的 MaterialApp
替换为 GetMaterialApp
即可,如下:
1 | class MyApp extends StatelessWidget { |
「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
本文将通过 Getx 的源码剖析 Getx 依赖管理的具体实现,带你一步一步的了解 Getx 的依赖管理原理,从而在开发过程中灵活使用 Getx 的依赖注入。
之前写了一篇文章介绍 Getx 的集成和使用:Flutter应用框架搭建(一)GetX集成及使用详解 ,里面有介绍 Getx 依赖管理的使用。主要包括 注入依赖
和 获取依赖
,关键方法如下:
1 | ///注入依赖 |
下面将通过这几个方法跟踪源码详细了解 Getx 依赖注入的原理。
本文将讲述怎么通过 MySql 的日志 binlog 文件进行数据恢复。
通过已备份数据 加上 binlog 文件恢复上次备份到删除之间的数据
进入 mysql 命令行执行如下命令
1 | mysql> show master status; |
一般最新的编号大,上面最新的就是 binlog.000002
这里有两种方式来确定开始位置和结束位置,一种是使用时间作为开始结束,一种是使用日志的 position
作为开始结束位置
LiveData 是Jetpack中的一个组件,是一个可被观察的数据存储器类, 具有感知组件生命周期的能力,LiveData 可以感知组件生命周期活跃状态发送数据更新,在组件销毁时移除观察者对象,大多结合具有生命周期的组件一起使用(如 Activity、Fragment 或 Service,或实现了 LifecycleOwner 接口的对象)。
那么 LiveData 有什么用呢?主要有如下两个作用:
LiveData 采用的是观察者模式,当 LiveData 保存的数据发生变化时就会通知观察者,观察者接收到通知后可以进行 UI 数据刷新或者其他操作。
那它是怎么做到防止内存泄漏的呢 ?在给 LiveData 添加观察者对象的时候可以绑定一个具有生命周期的组件,当组件生命周期处于活跃状态(即 STARTED 、RESUMED 状态)时数据更新才会通知观察者,当组件被销毁时则会自动移除对应的观察者对象,从而防止一直持有对应组件防止内存泄漏。
Google 2018 IO大会推出了Android新的扩展库AndroidX,用于替换原来的Android扩展库,将原来的android.*
替换成androidx.*
:.
Old | New |
---|---|
android.support.** | androidx.@ |
android.databinding.** | androidx.databinding.@ |
android.design.** | com.google.android.material.@ |
android.support.test.** | (in a future release) androidx.test.@ |
android.arch.** | androidx.@ |
android.arch.persistence.room.** | androidx.room.@ |
android.arch.persistence.** | androidx.sqlite.@ |
Paging是Google 2018 IO大会最新发布的Jetpack中的一个组件,主要用于大数据的分页加载,这篇文章就来探索一下关于Paging的简单使用。
Paging主要由三个部分组成:DataSource
PageList
PageListAdapter
DataSource<Key, Value>
从字面意思理解是一个数据源,其中key
对应加载数据的条件信息,Value
对应加载数据的实体类。DataSource
是一个抽象类,但是我们不能直接继承它实现它的子类。但是Paging库里提供了它的三个子类供我们继承用于不同场景的实现:
PageKeyedDataSource<Key, Value>
:适用于目标数据根据页信息请求数据的场景,即Key
字段是页相关的信息。比如请求的数据的参数中包含类似next/previous
页数的信息。ItemKeyedDataSource<Key, Value>
:适用于目标数据的加载依赖特定item的信息, 即Key字段包含的是Item中的信息,比如需要根据第N项的信息加载第N+1项的数据,传参中需要传入第N项的ID时,该场景多出现于论坛类应用评论信息的请求。PositionalDataSource<T>
:适用于目标数据总数固定,通过特定的位置加载数据,这里Key是Integer类型的位置信息,T即Value。 比如从数据库中的1200条开始加在20条数据。PageList
是一个List的子类,支持所有List的操作,除此之外它主要有五个成员:mMainThreadExecutor
: 一个主线程的Excutor, 用于将结果post到主线程。
mBackgroundThreadExecutor
: 后台线程的Excutor.
BoundaryCallback
:加载Datasource中的数据加载到边界时的回调.
Config
: 配置PagedList从Datasource加载数据的方式, 其中包含以下属性:
pageSize
:设置每页加载的数量prefetchDistance
:预加载的数量,默认为pagesize
initialLoadSizeHint
:初始化数据时加载的数量,默认为pageSize*3
enablePlaceholders
:当item为null是否使用PlaceHolder展示PagedStorage<T>
: 用于存储加载到的数据,它是真正的蓄水池所在,它包含一个ArrayList<List
PagedList会从Datasource中加载数据,更准确的说是通过Datasource加载数据, 通过Config的配置,可以设置一次加载的数量以及预加载的数量。 除此之外,PagedList还可以向RecyclerView.Adapter发送更新的信号,驱动UI的刷新。