扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
APP 启动页在国内是最常见也是必备的场景,其中启动页在 iOS 上算是强制性的要求,其实配置启动页挺简单,因为在 Flutter 里现在只需要:
成都创新互联于2013年创立,是专业互联网技术服务公司,拥有项目成都做网站、网站设计、外贸营销网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元商州做网站,已为上家服务,为商州各地企业和个人服务,联系电话:028-86922220
一般只要配置无误并且图片尺寸匹配,基本上就不会有什么问题, 那既然这样,还有什么需要适配的呢?
事实上大部分时候 iOS 是不会有什么问题, 因为 LaunchScreen.storyboard 的流程本就是 iOS 官方用来做应用启动的过渡;而对于 Andorid 而言,直到 12 之前 windowBackground 这种其实只能算“民间”野路子 ,所以对于 Andorid 来说,这其中就涉及到一个点:
所以下面主要介绍 Flutter 在 Android 上为了这个启动图做了哪些骚操作~
在已经忘记版本的“远古时期” , FlutterActivity 还在 io.flutter.app.FlutterActivity 路径下的时候,那时启动页的逻辑相对简单,主要是通过 App 的 AndroidManifest 文件里是否配置了 SplashScreenUntilFirstFrame 来进行判断。
在 FlutterActivity 内部 FlutterView 被创建的时候,会通过读取 meta-data 来判断是否需要使用 createLaunchView 逻辑 :
是不是很简单,那就会有人疑问为什么要这样做?我直接配置 Activity 的 android:windowBackground 不就完成了吗?
这就是上面提到的时间差问题, 因为启动页到 Flutter 渲染完第一帧画面中间,会出现概率出现黑屏的情况,所以才需要这个行为来实现过渡 。
经历了“远古时代”之后, FlutterActivity 来到了 io.flutter.embedding.android.FlutterActivity , 在到 2.5 版本发布之前,Flutter 又针对这个启动过程做了不少调整和优化,其中主要就是 SplashScreen 。
自从开始进入 embedding 阶段后, FlutterActivity 主要用于实现了一个叫 Host 的 interface ,其中和我们有关系的就是 provideSplashScreen 。
默认情况下它会从 AndroidManifest 文件里是否配置了 SplashScreenDrawable 来进行判断 。
默认情况下当 AndroidManifest 文件里配置了 SplashScreenDrawable ,那么这个 Drawable 就会在 FlutterActivity 创建 FlutterView 时被构建成 DrawableSplashScreen 。
DrawableSplashScreen 其实就是一个实现了 io.flutter.embedding.android.SplashScreen 接口的类,它的作用就是:
之后 FlutterActivity 内会创建出 FlutterSplashView ,它是个 FrameLayout。
FlutterSplashView 将 FlutterView 和 ImageView 添加到一起, 然后通过 transitionToFlutter 的方法来执行动画,最后动画结束时通过 onTransitionComplete 移除 splashScreenView 。
所以整体逻辑就是:
当然这里也是分状态:
当然这个阶段的 FlutterActivity 也可以通过 override provideSplashScreen 方法来自定义 SplashScreen 。
看到没有,做了这么多其实也就是为了弥补启动页和 Flutter 渲染之间, 另外还有一个优化,叫 NormalTheme 。
通过该配置 NormalTheme ,在 Activity 启动时,就会首先执行 switchLaunchThemeForNormalTheme(); 方法将主题从 LaunchTheme 切换到 NormalTheme 。
大概配置完就是如下样子, 前面分析那么多其实就是为了告诉你,如果出现问题了,你可以从哪个地方去找到对应的点 。
讲了那么多, Flutter 2.5 之后 provideSplashScreen 和 io.flutter.embedding.android.SplashScreenDrawable 就被弃用了,惊不喜惊喜,意不意外,开不开心 ?
通过源码你会发现,当你设置了 splashScreen 的时候,会看到一个 log 警告:
为什么会弃用?
其实这个提议是在 这个 issue 上,然后通过 这个 pr 完成调整。
大概意思就是: 原本的设计搞复杂了,用 OnPreDrawListener 更精准,而且不需要为了后面 Andorid12 的启动支持做其他兼容,只需要给 FlutterActivity 等类增加接口开关即可 。
也就是2.5之后 Flutter 使用 ViewTreeObserver.OnPreDrawListener 来实现延迟直到加载出 Flutter 的第一帧。
为什么说默认情况? 因为这个行为在 FlutterActivity 里,是在 getRenderMode() == RenderMode.surface 才会被调用,而 RenderMode 又和 BackgroundMode 有关心 。
所以在 2.5 版本后, FlutterActivity 内部创建完 FlutterView 后就会执行一个 delayFirstAndroidViewDraw 的操作。
这里主要注意一个参数: isFlutterUiDisplayed 。
当 Flutter 被完成展示的时候, isFlutterUiDisplayed 就会被设置为 true。
所以当 Flutter 没有执行完成之前, FlutterView 的 onPreDraw 就会一直返回 false ,这也是 Flutter 2.5 开始之后适配启动页的新调整。
看了这么多,大概可以看到其实开源项目的推进并不是一帆风顺的,没有什么是一开始就是最优解,而是经过多方尝试和交流,才有了现在的版本,事实上开源项目里,类似这样的经历数不胜数:
在说flutter国际化前,不得不提到,在uni-app中支持的Vue-i18n,两者有相似之处,也有差异的地方。
本篇借鉴了三篇热门帖子
Flutter中的国际化:如何写一个多语言的App
Flutter国际化完整例子
Internationalization - Make an Flutter application multi-lingual
只记录根据手机系统语言自动转换app语言
引入后,保存会自动加入安装此依赖
我们新建一个和"/lib"同级别的文件夹"/locale",然后在这个文件夹中新建两个文件,分别为"i18n_en.json" 和" i18n_zh.json"。再在"/lib"文件夹下创建和"main.dart"同级的"translation.dart"和"application.dart"。
文件夹树现在是这个样子的:
MyApplication
|
+- android
+- build
+- images
+- ios
+- lib
|
+-main.dart
+-translation.dart
+-application.dart
+- locale
|
+- i18n_en.json
+- i18n_zh.json
+- test
在pubspec.yaml继续加入json,引入静态资源
补充:如果需要强制转换的话(我自己没有用到)
不知道你要写哪方面的内容
帮你列了一些
National Day 国庆
golden week 黄金周
military parade 阅兵
tribute 赞颂
proclaim 宣布;公告
celebrate 庆祝
patriotism 爱国热情
triumph 胜利成功
explode fireworks 放礼花
the five-star flag flutter in the wind 五星红旗迎风飘扬
the 60th anniversary of the founding of the People's Republic 中华人民共和国成立60周年纪念
long live the motherland! 祖国万岁
stage a grand celebration 举办一场隆重的庆祝盛宴
display weaponry 展示武器
People's Liberation Army 人民解放军
这里有比较多的今年国庆的信息,你参考一下吧
你看看这个吧,比只知道西米的种类更能有启发
以下文章由台湾肚皮舞大师李梅林老师编写!
在梅林老师开始学肚皮舞技巧时,
对於Shimmy有著相当大的困惑,
看了许多网站以及文字资料,
Shimmy有著各式各样不同的名称以及派别,
说实在话,
当时我并不太清楚所学的Shimmy的由来以及派别,
直到近年,
慢慢跟著国外的老师学习,
并且看了许多相关资料,
对於Shimmy开始慢慢有了系统化的认识以及了解.
Shimmy这个动作所带来的成就,
也慢慢的在身体中形成.
虽跟国际大师的技巧来相比,
还有段距离,
但是对Shimmy的理解以及成就感,
让我有这种动力跟大家分享.
Shimmy并不是用力就可以做到的动作.
一个好的Shimmy技巧不仅是动作平均,
更是要稳定且持久.
从部落民族的生活型态演变到现代
Shimmy技巧已经远远超过最原始的动作型态,
现今舞者的Shimmy动作越来越花俏,
让人眼花撩乱,
但回归到最基本面,
Shimmy究竟可以分成多少种类呢??
Shimmy 的种类
Shimmy基本可区分成三大类 : (
第一类: Counting Shimmy(数拍Shimmy) 或 Walking Shimmy (走路Shimmy) qiuqiu注:hagallah也是此shimmy的一种
在美国,舞者多使用这种Shimmy,
Walking Shimmy的特色是由脚步(Step)搭配臀部动作,
主要使用的肌肉是臀肌,
利用重心脚的转换以及臀部上下方向的控制,
在固定的节奏下做出变化.
最常使用到的就是3/4 Shimmy ( Three Quarter Shimmy )
这种Shimmy简单的说,
即是在四拍的节奏中,
臀部以上下方向为主做出三拍动作,
在第四拍时空拍,
通常我都以”上-下-上-and” 或者 ”下-上-下-and “的指令教导学生
第四拍的and即为空拍,
舞者必须学著在第四拍时控制住臀部不动,
左右臀部相互轮流,
在速度慢时,
可以很清楚的看到舞者臀部与节奏之间的关系,
但速度加快时,
臀部的动作看起来就很类似Shimmy,
也是为何称之为Counting Shimmy.
此种Shimmy若练习的好,
看起来相当好看,
但若臀部节奏动作不够熟练,
或者脚步重心转换不够俐落,
看起来就会很糟糕.
这种Shimmy因为以臀部肌肉为主,
并搭配重心脚的转换,
让舞者可以很轻松的移动,
所以才又称之为Walking Shimmy.
有的舞者会加些变化在基本的3/4 Shimmy中,
比如会在臀部上下的同时加上臀部外推,
看起来臀部动作就相当大,
有些舞者称之为Ghawazee Shimmy,
或者加上臀部往前画圆的变化,
这个动作即为大家所熟知的Hagallah,
若臀部加入Maya的动作,
强调侧腹肌与臀部的同时使用,
即为Rachel Brice最常用的Over Shimmy,
相当有趣!!
为什麼这种Shimmy现在在美国相当受欢迎,
而非在中东国家(埃及,土耳其,黎巴嫩)呢??
在60.70年代时,
埃及的舞者是以Walking Shimmy没错,
也常常在埃及歌舞片中看到,
此种Shimmy最早是埃及传统民俗舞蹈中所发展出来的,
且仅有男性舞者会表演,
女性舞者是不会此种技巧的.
有趣的是,
埃及当地教授传统民俗舞蹈的老师并不认为这是Shimmy的一种,
会在美国开始流行,
主要是是70年代的舞蹈大师Jamila Salimpour
从埃及歌舞片中看到这种Shimmy之后,
撷取成为她个人教学系统里面的一环,
命名为3/4 Shimmy,
持续不断的指导学生练习,
这麼多年来影响相当多的舞者以及老师,
也让70年代当时没有太多教学经验的老师们开始重视系统化教学,
将此种Shimmy传承至今,
尤其是跳部落风格舞蹈的舞者,
使用的Shimmy多是此种Walking Shimmy.
也是为何美国舞者多是使用此种Shimmy的最主要原因.
顺带一提,
另外还有一种与3/4 Shimmy相当接近的Shimmy
即是2/4 Shimmy,
刚开始学生还无法掌握3/4 Shimmy技巧时,
通常都会作成2/4 Shimmy.
此动作就是四拍当中做两拍往上或者往下的动作.
不过此动作速度加快时,
美感不如3/4 Shimmy,
建议大家勤练3/4 Shimmy,
对技巧上的精进有相当大的帮助!!!
第二类: The Leg Shimmy(腿部Shimmy) 或 Knee Shimmy (膝盖Shimmy)
此种Shimmy除了上述的两种说法之外,
也有Lebanese Shimmy (黎巴嫩Shimmy)
Straight Legged Shimmy (腿部打直Shimmy)等不同的名字
但基本上都是以大腿或者膝盖为主要施力点.
严格的说,
在70年代之前历史上没有此种Shimmy.
是70年代之后才开始在埃及发展出来的,
所以通常也称之为Egyptian Shimmy,
对於此种Shimmy的起源,
目前有两种说法,
一种说法是在70年代,
由埃及三位大师- Ibrahim Akef , 以及Raqia Hassan所创,
另一种说法是90年代中,
Raqia Hassan在大师营教导授课时,
她忽略了说明Shimmy这个动作,
她的学生以为是利用膝盖的前后拍打带动臀部动作,
便一直沿用到现在.
此种Shimmy主要是由腿部的前后拍打动作带动臀部,
臀肌基本上是不必使力的,
仅透过腿部打直的大腿快速前后拍打,
臀部自然就会著腿部开始震动,
也是为何称之为The Leg Shimmy,
也有些舞者在做此动作时,
是透过膝盖前后拍打,
也会有同样的效果,
所以称之为Knee Shimmy.
如果力道大的话,
舞者不仅是臀部,
上半身至头顶甚至於头发都会随之震动,
此种Shimmy称之为Whole-Body Shimmy (全身Shimmy)
或者Earthquake Shimmy (地震Shimmy) !!
因为此种Shimmy主要是以膝盖为发动力点,
舞者比较容易练习上手,
也可以比较长时间做此动作.
但舞者在表演时很难同时移动,
也无法做出Level Change(高度)的变化,
下次观赏舞者表演时,
你会发现,
埃及风格的舞者多是停留在定点之后才做此Shimmy,
且绝对不会有高度变化.
虽没有高度以及移动变化,
此种Shimmy却加入了臀部水平绕圈的变化
" Horizontal Circle Shimmy "
也就是臀部一边水平绕圆一边Shimmy.
并搭配节奏做出不同强弱力度,
也有舞者喜欢表演One Leg Shimmy,
将重心放在单脚上,
另一只脚脚尖下压并打直,
以膝盖做出微小拍打,
让侧边身体可以作出细致的Shimmy动作,
并搭上变化多端的手势以及手臂动作
这几个动作相当的好看,
许多舞者喜欢这些技巧,
可以看出舞者在肌肉以及力道上的控制.
如果舞者的大腿或者膝盖的力道没有控制好,
又刚好穿著较短或者较紧的裙子,
那视觉效果可就大打折扣了….
此种Knee Shimmy跟Walking Shimmy比较起来,
初入门的舞者者比较容易上手,
但此种Shimmy近年来争议较多,
主要是因为长期过度使用膝盖,
对舞者的身体有相当的伤害,
不过也有些埃及的舞者强调,
即便是Knee Shimmy,
腿部也并非打直,
还是需要略为屈膝以保护膝盖,
各方说法不同,
但练习时还是以保护自己身体为主要前提.
第三类: The Hip Vibration Shimmy (臀部震动Shimmy) 或 Glutes Shimmy (臀肌Shimmy)
此种Shimmy与前两项Shimmy不一样的是,
既不用膝盖,也不用臀部上下移动来做出Shimmy变化,
仅用人类身体中面积最大的肌肉-臀肌做出来的技巧.
所以称之为Hip Vibration Shimmy.
此种Shimmy是臀部维持在同一位置
利用下臀肌(靠近大腿交界处)垂直往上提拉放松做出肌肉的变化.
也因为不需要与脚步(Step)配合,
所以做此种Shimmy时,舞者可以很轻松的移动,
也可以做出许多不同的高度变化,
有些舞者甚至可以坐在地板上展现此种Shimmy的技巧.
也因为仅使用到臀肌,
舞者也可以搭配身体其他肌肉,比如下腹肌等等,
做出各式各样的Shimmy变化.
相当好看.
此种Shimmy很多老师没有将之归类在教学中,
主要是许多老师还不清楚有此种Shimmy的存在,
甚或老师自己都还不会此种技巧,
也因为此种Shimmy的难度较高,
通常都是学习有一定程度之后老师才开始教授此技巧.
在练习Hip VibrationShimmy时,
要注意使用的肌肉区域仅在臀肌,
若直视镜子,
臀部(骨盆)从头到尾都不会有任何上下或者平移的变化,
从侧面看镜子,
会看到臀肌上提下放,
站立时需要屈膝,
大腿放松,
坐在地板上练习也是一个好方法,
但注意大腿要放松,
仅用臀肌往上提拉及放松,
身体其他部位都不动
也因为身体几乎都不动,
此种Shimmy也有人称之为Freeze Shimmy.
当左右臀肌可以跟著节奏变化时,
速度也可以跟著加快,
所以肌肉力道可以控制住时,
就可以跟著节奏速度加以变化,
但也有的舞者觉得,
因为动作太小,
所以若表演场合跟观众有所距离时,
观众可能很难察觉舞者此种细小动作.
此种Shimmy的起源也说法不一,
一种说法是从埃及,
在埃及,
部分舞者也会使用此种Shimmy,
主要是搭配Kanoon或者Oud等弦乐器,
展现小巧变化的舞蹈技巧,
埃及地区的部分舞者也称此种技巧为”Rashe”.
另一种说法是起源於非洲,
在非洲许多部落民族会模仿大自然界中的动物,
并在仪式舞蹈中呈现.
几个世纪前,
非洲裔人民大量移至美洲以及中美洲,
也将此动作带入了生活中,
若有机会到牙买加等中美洲旅游,
你将会很惊讶牙买加舞者对於Hip VibrationShimmy技巧之高超,
绝对颠覆埃及舞者以及我们的想像!!!
第四类: Other Shimmy (其他Shimmy )
除了上述三种Shimmy之外,
其实还有许多种Shimmy,
这些Shimmy或是因为动作无法自成系统,
或是因为非臀部的动作,
或是因为特定国家舞者的特色而有所不同,
但我认为,
广义的接纳以及认识才能将眼界打开,
所以也将上述这些无法自成一个系统的Shimmy整理出来跟大家分享.
Upper Body Shimmy 上半身Shimmy
在Upper Body Shimmy中,
又包含了Shoulder Shimmy(肩膀Shimmy)、
Chest Shimmy(胸部Shimmy)、
Shoulder Thrust(肩膀振动)
以及African Shimmy(非洲Shimmy)四种不同的Shimmy.
Shoulder Shimmy是透过肩膀前后摆动所构成,
通常在做此动作时,
需注意施力点是以肩膀为主,
当速度加快时即变成Shoulder Shimmy.
与Shoulder Shimmy相当接近的动作是Chest Shimmy.
这个动作与Shoulder Shimmy比较起来,
动作幅度较小,也较显优雅.
主要是以后背肩胛骨处肌肉发动,
肩膀放松不动,
手臂也不动,
仅有胸部微小的摆动,
故称之为Chest Shimmy.
上半身的Shimmy中也有一种Shoulder Thrust的变化式
是以Chest Shimmy为主,
但在动作上加上了肩膀上提的变化,
同时使用了后背以及肩膀两块不同的肌肉,
通常在教学生时,
我都以”上-前-上-后”的指令引导学生练习,
要将Shoulder Thrust练到优雅且好看,
需要花些时间以及精力,
一旦练起来,
此动作真的相当好看.
最后一种是在台湾比较少见的,
主要是利用上腹部的肌肉快速将胸部上提下放,
连著带动上半身的震动,
称之为African Shimmy.
还有一种有些老师不归类在Upper Body Shimmy中,
但我想跟大家一提的就是Flutter(腹部拍动),
这个动作是透过上腹肌快速的内收外放,
同时带动下腹肌做出有如蝴蝶翅膀快速拍动的动作,
而有Shimmy的效果.
这个动作我曾2005年在东京与Rachel Brice请教过,
依照她的方式,
需闭气练习此动作,
所以当我看到Rachel Brice可以面不改色
一边跳舞一边至少做四个八拍的Flutter,
对她可是相当的佩服.
Twist Shimmy 扭动Shimmy
许多舞者都很熟悉的Twist Shimmy,
也有人称之为Tunisian Shimmy (突尼西亚Shimmy)
此动作臀部需保持水平往右前方对角线平推之后,
再往右后方对角线平拉,
左右两侧轮流,
速度快时身体也会有些微的摆动,
在美国有些舞者称之为Washing Machine Shimmy
(洗衣机Shimmy)
但也有些人觉得这与Shimmy的文字定义不太相同,
并不将此动作归类於Shimmy.
Pelvic Shimmy 骨盆Shimmy
这可以算是Hip Shimmy中的变化式,
主要利用下腹部的肌肉提拉,
而不用到腰部肌肉以及臀部肌肉,
让骨盆自然前顷后提,
当下腹肌用力内收上提时,
骨盆自然往前,腰椎与脊椎成一直线,
但臀肌要放松,
下腹肌放松时,
骨盆即自然往后倾,
因为做这动作臀肌是放松的,
所以可以轻松加上Hip Shimmy,
即成Pelvic Shimmy.
Pelvic Drop Shimmy 骨盆下放Shimmy
这种土耳其特有的Shimmy,
与Pelvic Shimmy相当接近,
舞者同样使用下腹肌肉,
但动作较快速且小巧的让骨盆快速下放,
做出Shimmy的效果.
各位可观看下列影片,
看看舞者是怎麼做出这个漂亮的Pelvic Drop Shimmy
Bouncing Shimmy 跳跃Shimmy
这也是在土耳其舞者表演中常看到的Shimmy,
这种全身的Shimmy,
与埃及Knee Shimmy可以做到全身不太一样.
Bunching 是透过身体上下震动达到效果,
通常舞者做此动作时多透过脚踝,
上下踮带动身体垂直的震动,
虽脚部动作微小,
但却可以透过身体将震波扩大,
效果相当不错!!
现代的Shimmy种类相当多种类,
我在这边仅以我所阅读以及理解的方式加以整理,
其实还有许许多多Shimmy无法一一介绍,
但也希望这篇文章可以让不论初入门者,
或者各个舞者,
对Shimmy这个肚皮舞中,
相当重要的技巧有所认识以及了解.
Fluttercoin(简称FLT)中文名称是彩蝶币,是一种加密货币或一种数字资产。
本文面向 Flutter 初学者,旨在用易懂的方式带大家入门。除了 Flutter 代码,还会介绍到语法、原理、特性等基础知识。相信本文能帮助你学习和理解 Flutter。
我们先看一下目前的一些跨平台方案,从前端渲染的角度来分类的话,大致可以分为以下几种方案。
WebView 渲染
这种方案就很好理解,现在很多项目都会嵌入 H5 的页面。就是用 JavaScript 等前端技术进行开发,在客户端上用 WebView 来进行渲染。微信小程序目前使用的就是这种方案。
它的优点很明显,使用成熟的前端技术进行开发,学习成本低,开发效率高,并且支持动态发布代码。
但缺点也很明显,在性能体验上,和原生还是存在较大差距的。
原生控件渲染
既然 WebView 的性能不够好,于是就有了使用原生控件进行渲染的方案。这种方案,同样也是使用 JavaScript 开发,区别是它最终是调用原生控件进行渲染的。这种方案的代表是 Facebook 的 React Native。
由于使用原生控件进行渲染,性能体验也会更接近原生。但也只是更接近,和原生还是有差距的,因为它需要频繁的进行 JavaScript 和原生之间的通信,这个通信效率是比较低的。
另外,由于需要适配各个平台的控件,那就有可能出现,系统控件更新了,而框架本身还没有更新,由此产生了一些问题。换句话说,这种方案是受到原生控件限制的。
绘图引擎渲染
接下来就是主角了。
在前端,如果完全不使用原生控件,我们可以通过系统的绘图 API 绘制出一个用户界面。从这个角度出发,可以在各个平台使用一个统一接口的绘图引擎来进行界面绘制,这个引擎最终调用的是系统的 API 绘制的。这样的话,它的性能可以做到接近原生,并且又不受原生控件的限制,在不同平台上能够做到 UI 统一。
Flutter 就是这样的一个开发框架。
一个跨平台 UI 解决方案
Flutter 是由 Google 开发的,一个跨平台 UI 解决方案。换句话说,它原则上只管 UI 的问题,如果涉及到平台本身的一些功能,比如调用蓝牙、摄像头,一般还是需要原生代码去操作。但现在也会有一些第三方库帮我们解决这些问题。
绘图引擎 Skia
Flutter 使用 Skia 作为它的绘图引擎。Skia 已经被 Google 收购,目前很多 Google 旗下的产品都是用 Skia 绘制的,包括 Android。
Android 内置了 Skia,但 iOS 没有,所以在打 iOS 安装包的时候,会把 Skia 一起打进去。这就导致了,用同一份 Flutter 代码打包之后,iOS 的包要比 Android 的包大一些。
开发语言 Dart
Flutter 使用的开发语言,叫 Dart。Dart 也是 Google 自家的,它是一门面向对象的语言,从它身上会看到一些其他开发语言的影子。学习起来难度不大的。
前面讲跨平台方案的时候,可以发现别的方案基本都是用 JavaScript 作为开发语言的,但为什么 Flutter 不用?就因为 Dart 是谷歌自家的吗?这个问题先留着,我们后面会提到。
这里部分就简单点带过了,具体的搭建流程可以在官网查看:
主要的搭建步骤如下:
下载 Flutter SDK
官网下载地址:
由于在国内访问可能受限,官方为中国开发者搭建了镜像:
更新环境变量
解压后,将 flutter\bin 的全路径添加到环境变量 PATH 中。
安装开发工具
理论上,任何文本编辑器都可以用来开发 Flutter 应用,但推荐的开发工具是 Android Studio、IntelliJ 以及 VS Code。因为在这些开发工具上,可以安装官方的 Flutter 和 Dart 插件,得到更好的开发体验。文章里使用 Android Studio 来演示。
如果你打算开发 iOS 应用,则还需要安装 Xcode。
安装插件
在开发工具的插件设置中,安装上面说到的 Flutter 和 Dart 插件。Flutter 插件用于支持 Flutter 的运行、调试、热重载等功能,而 Dart 插件则提供了代码的输入校验、代码补全等功能。
万物始于 Hello World,我们先来创建一个显示 Hello World 的 Flutter 项目。
在 Android Studio 的欢迎页面选择 Start a new Flutter project ,或者通过菜单栏的 File New New Flutter Project ,创建一个新的 Flutter 项目。
创建好的项目里面包含了 android 和 ios 两个文件夹,它们是标准的 Android 和 iOS 项目。我们的 Flutter 代码,存放在 lib 文件夹里。项目创建好后,会默认带一个计数器的示例,我们不管它,把 main.dart 的代码改成 Hello World:
启动一个模拟器,或者连上真机,点击 Run 运行一下,就能看这样一个界面了:
具体代码先混个眼熟就好,具体的后面会再讲到。
在写 Flutter 之前,还要先跟大家简单介绍一下 Dart 的语法。如果你有 Java 或 JavaScript 的开发经验,以及面向对象的编程思想,学起来是很快的。
我们可以在 test 文件夹下新建一个 dart 文件,用来写测试代码。
指定类型
var
但和 JavaScript 不同的是,以下代码在 JavaScript 是不会报错的,但在 Dart 里会报错:
Object
如果非要上面这样写,那也可以。把 var 换成 Object 就不报错了:
和 Java 类似,Object 是所有对象的根基类。但是这样的话,如果想打印一下 num 的字符串长度,是会报错的:
因为 length 是属于 String 的,但系统只知道 num 是一个对象,并不知道它是一个 String。
dynamic
如果还是非要这样写,那也可以。Dart 有一个特有的关键字 dynamic,把 Object 改成 dynamic 就不报错了:
我们运行一下这个文件,可以在控制台看到正确打印出了字符串长度。
函数
dynamic
在 Dart 里,函数也是可以不写返回类型的,不写的话会被当做 dynamic 来处理。这样的话,函数的类型就是 return 的类型,如果没有 return 则是 void 类型。比如可以这样:
运行之后是能正确打印出字符串长度的。
用于传参
Dart 里的函数也是一个对象,所以可以把函数作为参数来传递,比如:
可选参数
在 Dart 的函数传参里,有一个叫可选参数的概念,我们以文字控件 Text 为例,在源码里可以看到 Text 的构造函数是这样的:
首先,在参数里有一个 data,它是要显示的文字内容,是一个必填项。而 data 后面的一堆参数,是用一个大括号括起来的,这些参数就叫做可选参数,意思是这些参数可传可不传。
假如我们要显示一个比较长的文字,又想限制它最多显示两行,就可以这样来创建一个 Text:
可选参数,在 Flutter 里面用的非常多。
异步
Future
在 Dart 里使用 Future 来处理异步任务,比如我们现在延时一秒打印 666,代码如下:
Future 的语法和 Promise 非常像。任务执行成功会调用 then,执行失败会调用 catchError,而无论成功还是失败,都会调用 whenComplete。
async/await
如果你不喜欢上面那种写法,或者是想把异步转成同步,就可以用 async 和 await 这两个关键字来转换。
我们把上面的代码转换一下,写一个 getString 方法,返回的类型是 Future,它会延时返回一个字符串。在 main 函数后面加上 async 关键字,在 getString() 前面加上 await,代码如下:
运行之后可以看到,能正常延时一秒后,把字符串打印出来。这里 getString() 返回的类型是 Future,而 await getString() 则是返回了延时之后返回的字符串。await 要在 async 的函数里面才能使用。
async 和 await 其实是一个语法糖,它最终也是转换成 Future 调用链的形式执行的。
接下来回到 Flutter,Flutter 里最重要的一个概念是 Widget(下面翻译作控件)。
在原生开发里面,我们可能会在界面上区分,这是一个 View,这是一个 Layout,这是一个 View Controller。但在 Flutter 里面,它们全都属于一个统一的模型 Widget。可以说,在 Flutter 界面里,所有东西都是 Widget。
以前学面向对象的时候,我们都听过一句话,叫万物皆对象。我这里套用一下,在 Flutter 里, 万物皆控件 。
具体有哪些控件,我做了一下简单的分类。
根控件
所有的控件都属于 StatefulWidget 或 StatelessWidget 。它们的区别是,StatefulWidget 拥有状态 State ,而 StatelessWidget 没有。
StatefulWidget
当一个控件是可变的时候,就要使用 StatefulWidget 来构建。StatefulWidget 本身不可变,但它持有的状态 State 是可变的。
StatelessWidget
当一个控件状态是固定不可变的时候,就可以使用 StatelessWidget。前面我们写的 Hello World 就是使用 StatelessWidget。
容器控件
容器类控件一般是将某些属性或配置,作用在它的子控件上,比如控件所在的宽高、背景、位置等。
常用的容器控件有 Container、Center、Padding 等。
布局控件
布局控件可以类比作原生开发中的 Layout,通常它会拥有一个 children 的属性,用于接收一个控件数组,对这些控件进行特定的排版。
常用的布局控件有 Row、Column、Stack、Flex 等。
基础控件
基础控件就是常用的文字、按钮、图片等控件。
常用的基础控件有 Text、TextField、Button、Image 等。
功能控件
在 Flutter 里还有一类控件,它们不影响 UI 布局,但带有一些特定的功能,比如页面跳转、事件监听、定义主题等。我们把这一类控件称作功能控件。
常用的功能控件有 Navigator、NotificationListener、Theme 等。
开始写 Flutter 代码了。还记不记得,在 Flutter 项目创建之后,是自带一个计数器 demo 的,现在我们用自己的代码实现一遍。代码修改成如下:
运行之后,就可以看到这样的界面了:
按钮每点击一次,数字就会加一。下面我们来分析一下这段代码,看下里面用到的一些 Widget。
StatefulWidget
由于页面中的数字是跟随状态变化的,所以该页面改用 StatefulWidget。StatefulWidget 并不会直接返回一个 Widget,而是返回状态 State,在 State 里再返回 Widget。
Scaffold
Scaffold 是一个标准的 Material Design 页面,它包含了标题栏、浮动按钮、侧滑菜单、底部导航栏等配置。我们这里用到了标题栏 appBar、页面内容 body、浮动按钮 floatingActionButton。
AppBar
AppBar 就是标题栏,通过查看控件的构造方法,我们可以知道它可配置的属性。
AppBar 的可选参数除了标题 title,还可以配置标题前的内容 leading,右侧的操作按钮 anctions,控件垂直高度 elevation 等。我们只传了 title,其他属性都用默认值。
Center
Center 是一个容器类控件,它的作用就是让它的子控件居中显示。
FloatingActionButton
熟悉安卓开发的应该对这个控件比较熟悉,它就是页面右下角一个特定样式的 Button,参数里面的 onPressed 是一个必填项,要传一个点击之后的回调函数。
根据这个例子,下面给大家介绍一下 Flutter 两个比较重要的特性。
点击 Button 之后,我们把 num 变量加一,并使用 setState 通知状态发生了改变,Flutter 会根据新的状态更新 UI。如果有接触过小程序开发,setState 就和小程序的 setData 类似。
在 Flutter 里面我们不需要用 set 方法来更新 UI,可变控件是和状态绑定的,这就是 Flutter 的响应式 UI 编程。
在 Android Q 和 iOS 13 里都加入了暗黑模式,我们也换一个暗黑主题来玩一下。MaterialApp 里有一个 theme 的属性,我们把它配置一下:
这次改完之后不点 Run 了,我们点一下闪电图标 Flutter Hot Reload ,就能看到界面发生了变化:
这就是 Flutter 的 热重载 ,在修改完代码之后,通过热重载就能马上在设备上看到修改结果,可以很大程度上增加开发效率。
下面再给大家介绍几个 Flutter 里的常见操作。
在 Flutter 里,使用 Navigator 来管理页面跳转,比如要跳转到一个 NewPage 可以这样写:
进栈使用 push,出栈则是 pop。
使用 MaterialPageRoute 会模拟出 Android 上页面跳转的过场效果。
我们来看看怎么显示一张本地图片。
先在根目录新建一个存放图片的文件夹,比如叫 images,把图片 picture.png 放进去。
找到根目录下的 pubspec.yaml 文件,这个便是 Flutter 依赖配置文件,我们需要在这里配置一下刚才的图片:
这样,我们就能使用 Image 控件把这张图片显示出来了:
和 node 的 npm 以及 Android 的 jcenter 类似,Flutter 也拥有一个公共仓库 pub.dev。pub.dev 是 Google 官方的 Dart 仓库,在上面可以找到我们需要的包和插件。
Flutter 本身没有 Toast,我们来接入一个。在 pub.dev 上搜索后,我决定使用 fluttertoast:
按照说明,在 pubspec.yaml 文件里的 dependencies 下配置:
点一下 Android Studio 右上角的 Packages get 同步之后就可以使用了:
我们上面使用的都是 Material Design 的控件,它们都是在 flutter/material.dart 包里面的。如果要使用 iOS 风格的控件,则要用到 flutter/cupertino.dart 包:
iOS 风格的控件,基本都以 Cupertino 开头。我们把计时器页面里的控件替换一下:
效果如下:
代码的部分就到这里了,接下来跟大家聊一下编译方式,编程语言的编译方式有两种。
关于它们孰优孰劣,就要看从哪个角度去对比了。JIT 的话,它的一大特点就是支持动态发布代码,也就是支持热更新。但要是从性能的角度考虑,AOT 会更好,因为在运行的时候不用再进行编译的操作的,运行的效率会更高一些。
回到我们一开始的时候留下的问题,为什么别的跨平台方案都是用 JavaScript,而 Flutter 要用 Dart 来开发。JavaScript 的编译方式是 JIT 的,它不支持 AOT。而 Dart 同时支持 JIT 和 AOT。
Flutter 在开发阶段使用 JIT,让我们用上了热重载,增加了开发效率。在打包时改用 AOT,保证了正式版应用的性能。
最后讲一下大家比较关心的一个东西,Flutter 是否支持热更新?前面说到 Dart 支持 JIT,所以从技术层面它是支持的。但是目前是不支持的,在官方的计划文档中,可以看到:
至于原因,官方在这里进行了说明。总的来说,是由于政策的限制,以及出于对性能和安全性的考虑,暂时不支持了。
到这就结束啦。由于想把 Flutter 基础在一篇内讲完,没有涉及太多细节,如果要写 Flutter 代码还需要深入学习。但相信理解之后再学,会轻松很多。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流