一个 iOS 开发者的 Flutter“历险记”

2019-05-17 16:01:20 +08:00
 MobService

1、 官方简介

Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。

官方介绍: 快速开发: 毫秒级的热重载,修改后,您的应用界面会立即更新。使用丰富的、完全可定制的 widget 在几分钟内构建原生界面。 富有表现力和灵活的 UI: 快速发布聚焦于原生体验的功能。分层的架构允许您完全自定义,从而实现难以置信的快速渲染和富有表现力、灵活的设计 原生性能: Flutter 包含了许多核心的 widget,如滚动、导航、图标和字体等,这些都可以在 iOS 和 Android 上达到原生应用一样的性能。

2、安装环境

①下载 FlutterSDK: https://github.com/flutter/flutter/releases

②配置 vscode 编辑器: https://flutterchina.club/get-started/editor/#vscode 附:vs 下载地址

③vscode 命令运行 flutter doctor,会提示你设置 flutterSDK 路径 (如果遇到权限问题需要用 Sudo chown 命令,如果遇到文件夹不存在需要手动创建对应的文件夹)

④构建第一个 Flutter 程序: 创建程序 :VSCode -> View -> Command palette : Flutter NewProject 运行程序 :Debug -> Start Debuging

注意事项 :如果遇到 Multiple commands produce 错误,cocoapods 导入问题,尝试修改 build system:在 Xcode 菜单栏 -> File -> Workspace Setting,将 build system 修改为 legacy build system,然后 clean 后编译。 ⑤Hello World!: void main() => runApp(Center(child:Text("hello,world!",textDirection: TextDirection.ltr))); Pubspec Format 介绍: https://www.dartlang.org/tools/pub/pubspec

3、Widget 介绍

官方布局介绍: https://flutterchina.club/tutorials/layout/

链接: https://flutterchina.club/widgets-intro/

基础 Widget: MaterialApp:该 widget 在应用程序的根部创建了一些有用的 widget,其中包括一个 Navigator, 它管理由字符串标识的 Widget 栈(即页面路由栈)。Navigator 可以让您的应用程序在页面之间的平滑的过渡。

Scaffold:实现 MaterialDesign 布局 Widget, 此类提供 tabbar,navigationBar 和 bottomSheets 等。

Row、Column: 这些具有弹性空间的布局类 Widget 可让您在水平( Row )和垂直( Column )方向上创建灵活的布局。其设计是基于 web 开发中的 Flexbox 布局模型。

Stack: 取代线性布局 (译者语:和 Android 中的 LinearLayout 相似),Stack 允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于 Stack 的上下左右四条边的位置。Stacks 是基于 Web 开发中的绝度定位( absolute positioning )布局模型设计的。

Container:Container 可让您创建矩形视觉元素。container 可以装饰为一个 BoxDecoration, 如 background、一个边框、或者一个阴影。Container 也可以具有边距( margins )、填充(padding)和应用于其大小的约束(constraints)。另外,Container 可以使用矩阵在三维空间中对其进行变换。

当然还有常用的其他一些 Widget 就不一一罗列了,exam:Padding、Image、Clip...

https://flutterchina.club/widgets/

但是有必要说一下:Cupertino 系列 Widget 是基于 iOS 设计语言的 Widget 风格

4、动画

官方详细介绍: https://flutterchina.club/animations/

个人总结: Flutter 动画不同于 iOS 动画,一个 block 执行一个动画

Flutter 的动画的核心类为: AnimationController:控制动画的开始,暂停,与结束,它不关心我在执行什么动画

Animation:这个是一个抽象类,决定动画的数据和变化方式等,可以通过 addListener 去监听其 Value 的变化,初始化的时候需要一个 AnimationController ;

开始一段动画过程: ①AnimationController.forward();//开始动画 ②Animation.value 发生变化,并执行 Animation.notifyListener() ③监听函数执行 setState() ④子 Widget 根据 Animation 的 value 值进行布局

总结:就是不停的根据 Animation 的变化进行 setState(),Flutter 的动画并不关心 Widget 的布局方式等,只提供动画的数据模型

5、界面跳转 使用了 Navigator 和 Routes。一个路由是 App 中“屏幕”或“页面”的抽象,而一个 Navigator 是管理多个路由的 widget。你可以粗略地把一个路由对应到一个 UIViewController。Navigator 的工作原理和 iOS 中 UINavigationController 非常相似,当你想跳转到新页面或者从新页面返回时,它可以 push() 和 pop() 路由。

两种方式跳转: △构建路由表 void main() { runApp(MaterialApp( home: MyAppHome(), // becomes the route named '/' routes: <String, WidgetBuilder> { '/a': (BuildContext context) => MyPage(title: 'page A'), '/b': (BuildContext context) => MyPage(title: 'page B'), '/c': (BuildContext context) => MyPage(title: 'page C'), }, )); }//跳转 Navigator.of(context).pushNamed('/b'); △直接通过 widget 创建一个路由 Navigator.push(context, new MaterialPageRoute( builder: (BuildContext context) => new FTShareHomePage(title: "ShareSDK Flutter Bridge"), // fullscreenDialog: true, )); △数据回传 //比如 push 到位置选择界面 Map coordinates = await Navigator.of(context).pushNamed('/location');//用户选择了位置 pop 出来 Navigator.of(context).pop({"lat":43.821757,"long":-79.226392});

6、Dart 中的异步

①先了解代码怎么写 Future<map> loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); return json.decode(response.body); }//调用 loadData().then((Map data){</map>

}); ② 原理其实不重要 (手动滑稽) 官方介绍: Dart 是单线程执行模型,但是它支持 Isolate (一种让 Dart 代码运行在其他线程的方式)、事件循环和异步编程。除非你自己创建一个 Isolate,否则你的 Dart 代码永远运行在 UI 线程,并由 event loop 驱动。Flutter 的 event loop 和 iOS 中的 main loop 相似—— Looper 是附加在主线程上的。 Dart 的单线程模型并不意味着你写的代码一定是阻塞操作,从而卡住 UI。相反,使用 Dart 语言提供的异步工具,例如 async / await,来实现异步操作。

7、与原生进行交互

官方介绍链接: https://flutterchina.club/platform-channels/

介绍 应用的 Flutter 部分通过平台通道( platform channel )将消息发送到其应用程序的所在的宿主( iOS 或 Android )。 宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的 API (使用原生编程语言)

代码示例(分享到第三方平台): dart 代码怎么写 //创建一个 channel static const channel = const MethodChannel('com.mob.flutter/sharesdk');// invokeMethod 方法执行原生方法 static Future<map> share(int platform, Map params) async { return await channel.invokeMethod("share", [platform, params]); } 原生层:</map>

8、开发 Package

官方介绍链接: https://flutterchina.club/developing-packages/

步骤: ①创建一个 Package 工程 flutter create --template=package hello#指定 org 可以自动创建平台桥接文件和 example 示例 path_to_fluttersdk/bin/flutter create --org com.yoozoo --template=plugin sharesdk ②实现 package:lib/<package name="">.dart 下为插件的 flutter 端代码,ios/Classes/HelloPlugin.m 下为 原生层实现代码,初始代码已有 bridge 示例</package>

③启动 xcode,插件 bridge 文件在 Pods/Development Pods/hello/Classes/下:在编辑 Xcode 中的 iOS 平台代码之前,首先确保代码至少已经构建过一次(例如,从 Xcode 中运行示例应用程序或终端执行 cd hello/example; flutter build ios --no-codesign )。

④自动生成 api 文档: cd package 工程目录 export FLUTTER_ROOT=~/dev/flutter$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dartdoc ⑤发布前检查: //过程会提示你完善 pubspec.yaml,关于 example 和 test 的警告可无视 flutter packages pub publish --dry-run ⑥发布: flutter packages pub publis

关于分包: 对于 ShareSDK 和支付这样的 Plugin 需要分包且 cocoapods 含有 subspec 的,需要开发者在设置完 dependences 后手动去 packageName.podspec 设置对应的依赖,然后运行 Flutter upgrade package

To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html#Pod::Spec.new do |s|

s.name = 'sharesdk_flutter' s.version = '0.0.1' s.summary = 'flutter plugin for sharesdk.' s.description = 'ShareSDK is the most comprehensive Social SDK in the world,which share easily with 40+ platforms.' s.homepage = 'http://www.mob.com' s.license = { :file => '../LICENSE' } s.author = { 'Mob' => 'mobproducts@163.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/' s.public_header_files = 'Classes/**/.h' s.dependency 'Flutter' s.dependency 'mob_sharesdk'# s.dependency 'mob_sharesdk/ShareSDKUI'# s.dependency 'mob_sharesdk/ShareSDKPlatforms/QQ'# s.dependency 'mob_sharesdk/ShareSDKPlatforms/SinaWeibo'# s.dependency 'mob_sharesdk/ShareSDKPlatforms/WeChat'# s.dependency 'mob_sharesdk/ShareSDKPlatforms/Facebook'# s.dependency 'mob_sharesdk/ShareSDKPlatforms/Twitter'

s.ios.deployment_target = '8.0'end 附: ShareSDK 官方 package 主页: https://pub.dartlang.org/packages/sharesdk

个人学习 Demo github 地址: https://github.com/vhbvb/Flutter_learn

ShareSDK package 开发 git: https://github.com/MobClub/ShareSDK-For-Flutter

392 次点击
所在节点    自言自语
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/565096

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX