概述
跨平台移动开发工具。
第一篇很长了,所以换到第二篇。第一篇主要写了安装、布局等基础性模块,第二篇涉及到更多模块
选择器
中国城市选择器
安装包
1 | dependencies: |
导入包
1 | import 'package:city_pickers/city_pickers.dart'; |
实例
文件选择器
安装包
1 | dependencies: |
引入包
1 |
实例
1 |
时间日期选择器
底部弹出栏,可以选择时间、日期,支持中文、英文等几种语言。
安装包
1 | dependencies: |
引入包
1 | import 'package:flutter/material.dart'; |
实例
1 | onPressed: () { |
https://www,jianshu.com/p/4b23964be383
动画
animation
1 | class _Animation extends State<AnimateApp> with SingleTickerProviderStateMixin{ |
Animation
对象,是 Flutter
动画库中的核心类,插入用于引导动画的值,Animation
对象知道当前动画的状态(如:动画是否开始,停止,前进或者后退),但对屏幕上显示的内容一无所知
AnimationController
对象管理着 Animation
CurvedAnimation
是非线性运动的动画
Listeners
和 StatusListeners
来监听动画状态的变化
controller常用方法
- animateTo(double target, { Duration duration, Curve curve: Curves.linear }) :将动画从其当前值驱动到目标值
- animateWith(Simulation simulation):根据给定的需要模拟的物体运动(类似物体的速度,受到的力等)开展动画
- dispose() :释放此对象使用的资源。调用此方法后,该对象不再可用。
- fling({double velocity: 1.0, AnimationBehavior animationBehavior }) :使用临界阻尼弹簧(在lowerBound 和upperBound内)和初始速度驱动动画。
- forward({double from }) :开始向前运行此动画(到最后)。
- repeat({double min, double max, Duration period }) :以向前方向开始运行此动画,并在完成时重新启动动画。
- reset() :将控制器的值设置为lowerBound,停止动画(如果正在进行中),并重置为其开始点或解除状态。
- reverse({double from }):开始反向运行此动画(朝向开头)。
- stop({bool canceled: true }):停止运行此动画。
AnimationStatus.completed表示动画结束的状态,AnimationStatus.dismissed表示动画回到起点的状态
- didRegisterListener():在添加动画状态监听前调用,该方法需融合withAnimationLocalStatusListenersMixin的类来实现
- addStatusListener(AnimationStatusListener listener):添加动画状态监听
- removeStatusListener(AnimationStatusListener listener):移除动画状态监听
- didUnregisterListener():在移除动画状态监听后调用,该方法需融合withAnimationLocalStatusListenersMixin的类来实现
- notifyStatusListeners(AnimationStatus status):动画状态变化的通知,通知所有注册的AnimationStatusListener
flutter页面切换时动画处理
1 | dependencies: |
引入
1 | import 'package:flutter_villains/villain.dart' |
动画分为两类,补间动画和物理动画
补间动画就是
Tween是一个无状态(stateless)对象,需要begin和end值。Tween的唯一职责就是定义从输入范围到输出范围的映射
物理动画是在基于物理的动画中,运动被模拟为与真实世界的行为相似。例如,当你掷球时,它在何处落地,取决于抛球速度有多快、球有多重、距离地面有多远。 类似地,将连接在弹簧上的球落下(并弹起)与连接到绳子上的球放下的方式也是不同。
flutter 的动画是基于
hero动画
在路由转换之间添加动画成为hero动画,hero动画为共享动画
flare动画
https://juejin.im/post/6861865147557183495#heading-5
实例1:闪屏动画
实例2:加载动画
3D动画
Flutter 中的 Transform 可以实现许多酷炫的动画效果,由于现在的智能手机都有用于图形计算的 GPU 单元,对于图形的计算与渲染进行了优化,因此即使是渲染 3D 图形也是非常快的。因此,基本上你看到的手机上的所有图形,都是通过 3D 的渲染方式来呈现的,即使是 2D 的图形素材。
通过 Transfrom 来实现透视效果,而 Transfrom 是通过 Matrix4 进行矩阵变换来实现的这个效果。
Grapgql
安装包
1 | dependencies: |
首先将json数据转换为dart模型
科学上网打开 转换 网站:app.quicktype.io/
将json代码数据粘贴到左侧,右侧选择dart语言,会自动生成模型代码
复制右侧代码,保存到dart文件中(如PostsData.dart)
实例
1 | import 'package:graphql_flutter/graphql_flutter.dart'; |
https://juejin.im/post/5ed5a4d46fb9a047cf332f83#heading-3
数据存储
把一些轻量级的数据(如用户信息、APP配置信息等)写入SharedPreference做存储,flutter中使用第三方库实现。合理地使用持久化能够让App支持离线化操作,给用户带来极大的操作体验的提升。
安装包
1 | dependencies: |
引入包
1 | import 'packages:shared_preferences/shared_preferences.dart' |
sp是通过key-value的方式存数据、取数据
1 | //存数据 |
把长期存储的数据写入文件或Sqlite3
写入文件
安装包
1 | dependencies: |
Sqlite
1 | dependencies: |
引入文件
1 | import 'package:sqflite/sqflite.dart'; |
Provider状态管理
InheritedWidget可以提供共享数据,并且通过getElementForInheritedWidgetOfExactType来解除didChangeDependencies的调用,但还是没有避免CountWidget的重新build,并没有将build最小化。
我们今天就来解决如何避免不必要的build构建,将build缩小到最小的CountText。
provider是一个依赖注入和状态管理的混合工具,通过组件来构建组件。
安装包
1 | dependencies: |
引入包
1 | import 'package:provider/provider.dart'; |
通过各种不同的provider来应对具体的需求
Provider
最基础的provider,它会获取一个值并将它暴露出来
ListenableProvider
用来暴露可监听的对象,该provider将会监听对象的改变以便及时更新组件状态
ChangeNotifierProvider
ListerableProvider依托于ChangeNotifier的一个实现,它将会在需要的时候自动调用ChangeNotifier.dispose
方法
ValueListenableProvider
监听一个可被监听的值,并且只暴露ValueListenable.value
方法
StreamProvider
监听一个流,并且暴露出其最近发送的值
FutureProvider
接受一个Future
作为参数,在这个Future
完成的时候更新依赖
暴露多个provider
1 | MultiProvider( |
selector
不要在只会调用一次的组件生命周期中调用Provider,如create、initstate
provider
暴露了许多细节api以便使用者封装自己的provider,它们包括:SingleChildCloneableWidget
、InheritedProvider
、DelegateWidget
、BuilderDelegate
、ValueDelegate
,
https://juejin.im/post/6844904145774870536#heading-10
Fishredux
安装fishredux
1 | dependencies: |
引入
1 | import 'package:fish_redux/fish_redux.dart'; |
reducer是负责(state)的更新,effect 负责 state 更新之外的事情。
store维持全局的状态(state),应用只有一个单一的 store 。
Bloc
状态管理插件
https://juejin.im/post/6844903689082109960#heading-4
路由
路由是在不同页面之间跳转。在Android中通常指一个Activity,在iOS中指一个ViewController。flutter中管理多个页面时有两个核心概念和类:Route 和 Navigator。一个 route 是一个屏幕或页面的抽象,Navigator 是管理 route 的 Widget。路由入栈 (push) 操作对应打开一个新页面,路由出栈 (pop) 操作对应页面关闭操作,
Navigator
是一个路由管理的组件,它提供了打开和退出路由页方法。Navigator
通过一个栈来管理活动路由集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator
提供了一系列方法来管理路由栈,
注册路由表
1 | routes:{ |
路由表是一个Map类型的键值对集合,key是路由的名字,是字符串,value是builder函数,
普通跳转方式与返回
1 | Navigator.push( |
MaterialPageRoute
是Material
组件库的一个Widget,它可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画
命名路由
一般推荐使用命名路由的方式管理路由,因为:
语义化更明确。
代码更好维护;如果使用匿名路由,则必须在调用Navigator.push
的地方创建新路由页,这样不仅需要import新路由页的dart文件,而且这样的代码将会非常分散。
可以通过onGenerateRoute
做一些全局的路由跳转前置处理逻辑。
方法
1 | Future pushNamed(BuildContext context, String routeName,{Object arguments}) |
路由参数
注册路由与正常相同,路由页与路由跳转添加参数
1 | class EchoRoute extends StatelessWidget { |
跳转路由时填写参数
1 | Navigator.of(context).pushNamed("new_page", arguments: "hi"); |
其他跳转方式
PushReplacement会替换当前的路由,也就是说新push进入的route会替换原来route。
PushReplacementNamed是根据路由名称(routeName),找寻对应的route,并实现见面的跳转。PushReplacementNamed
会替换当前的路由,也就是说新push进入的route会替换原来route。
PopAndPushNamed是先pop原来的route,再push新的route。
pushAndRemoveUntil/pushNamedAndRemoveUntil,,跳转到新的路由,并删除路由栈中的其他路由,可以应用于支付流程。在支付的过程中,我们会跳转多个界面(填写金额、选择支付方式、输入密码、支付结果…),当我们支付成功后,pop时不应该一层一层的,而应该直接返回根界面。
canPop判断当前route是否可以pop,返回bool;maybePop先判断当前route是否可以pop,可以则直接pop,不行则没有任何效果。
popUntil一直返回route,直到predicate
返回true时停止。
实例
1 | Navigator.of(context).pushNamed('a_router_widget'); |
路由钩子函数
时间组件
DateTime表示一个时间点,创建之后将是固定不变的,不可被修改,datetime默认是本地时区
1 | var today = DateTime.now()//获取当前时间 |
屏幕适配
瀑布流
安装包
1 | dependencies: |
导入包
1 | import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; |
使用包
1 | new StaggeredGridView.countBuilder( |
剪切板
https://jianshu.com/p/c71b150f85f0
引入包
1 | import 'package:flutter/service.dart' |
安装包
1 | dependencies: |
引入包
1 | import 'package:flutter_clipboard_manager/flutter_clipboard_manager.dart' |
实例
1 | //定义函数,写入剪贴板 |
国际化
使用intl包可以实现国际化,也方便
添加sdk
1 | flutter_localization: |
引入
1 | import 'packages:flutter_localization/flutter_localization.dart' |
权限管理
安装包
1 | dependencies: |
引入包
1 | import 'package:permission_handler/permission_handler.dart'; |
实例
1 | Future requestPermission() async { |
版本管理
安装包
1 | version |
引入包
SVG插件
可以在flutter中使用svg文件,安装包
1 | dependencies: |
引入包
1 | import 'packages:flutter_svg/flutter_svg.dart' |
实例
1 | //将svg格式的文件放在asset中,在yaml文件中引入资源 |
插入web_view
安装插件
1 | dependencies: |
引入
1 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart' |
实例
1 | new MaterialApp( |
网络状态
安装包
1 | dependencies: |
引入包
1 | import 'package:connectivity/connectivity.dart'; |
实例
1 | var connectivityResult = await (Connectivity().checkConnectivity()); |
地图组件
安装包
1 | dependencies: |
允许
1 | <uses-permission android:name="android.permission.INTERNET"/> |
引入包
1 | import 'package:flutter_map/flutter_map.dart'; |
保存图片
可以在flutter中保存图片,安装包
1 | dependencies: |
导入包
1 | import 'package:image_gallery_saver/image_gallery_saver.dart'; |
实例
1 | _save() async { |
键盘管理
安装包
1 | dependencies: |
引入包
1 | import 'package:keyboard_visibility/keyboard_visibility.dart'; |
实例
1 |
|
资源管理
flutter可以将asset打包在程序安装包中,在程序运行时访问,常见的资源包括json文件、配置文件、图标和图片。构建时flutter将asset放置到称为asset bundle的特殊存档。
在pubspec.yaml中 指定资源
1 | flutter: |
加载方法
1 | Image.asset('路径')//加载图片 |
1 | import 'package:flutter/services.dart' show rootBundle; |
加载依赖包中的图片
1 | AssetImage('icons/phone.png',package:'best_icons') |
指定某一目录的所有资源,直接指定目录名称
1 | flutter: |
搜索页
录音管理
安装包
1 | dependencies: |
引入包
1 | import 'package:audio_recorder/audio_recorder.dart'; |
开启权限
安卓
1 | <uses-permission android:name="android.permission.RECORD_AUDIO" /> |
IOS
1 | <key>NSMicrophoneUsageDescription</key> |
实例
1 | // 检查权限 |
长按复制
QQ和微信
手机震动
安装包
1 | dependencies: |
引入包
1 | import 'package:vibration/vibration.dart'; |
在AndroidManifest.xml文件中开启权限
1 | <uses-permission android:name="android.permission.VIBRATE"/> |
实例
1 | 震动函数以ms为单位, |
flutter美化进阶组件
液体效果页面切换
安装包
1 | dependencies: |
引入包
1 | import 'package:liquid_swipe/Constants/Helpers.dart'; |
https://juejin.im/post/5ddb54146fb9a07a8f412d62
点赞按钮动画
安装包
1 | dependencies: |
引入包
1 | import 'package:like_button/like_button.dart'; |
https://juejin.im/post/5db4f54bf265da4d02625c17
加载中过渡动画
安装包
1 | dependencies: |
引入包
1 | import 'package:liquid_progress_indicator/liquid_progress_indicator.dart'; |
圆形进度器
1 | LiquidCircularProgressIndicator( |
https://juejin.im/post/5dde3194f265da06074f13c6
粘性header组件
安装包
1 | dependencies: |
引入包
1 | import 'package:sticky_headers/sticky_headers.dart'; |
实例
1 | ListView.builder( |
可翻转卡片
安装包
1 | dependencies: |
引入包
1 | import 'package:flip_card/flip_card.dart'; |
实例
1 | FlipCard( |
自制刮刮卡效果
安装包
1 | dependencies: |
引入包
1 | import 'package:scratcher/scratcher.dart'; |
实例
1 | Scratcher( |
自制评分组件
安装包
1 | dependencies: |
引入包
1 | import 'package:flutter_rating_bar/flutter_rating_bar.dart'; |
实例
1 | RatingBar( |