初识flutter

偶然看见了移动端跨平台开发的深度解析这篇文章,里面提到的React-Native和weex或多或少都有了解,关于Flutter却了解甚少,于是决定体验一下。这篇文章主要用于初步尝试flutter开发的整理,包括开发步骤和遇见的一些问题。

在学习过程中写了一个练手的demo,放在github上了~

<!--more-->

参考文档

1. 准备工作

1.1. 安装

网上有大把教程进行安装,这里只是简单描述一下步骤就行了

  • 下载对应环境的flutter SDK,解压到本地
  • 配置flutter到环境变量,确保flutter命令可以使用
  • 运行flutter doctor检测开发环境
  • 欧了~

1.2. 语言

flutter采用Dart作为开发语言,关于Dart的相关语法,可以先看一下这篇教程

Dart是一门很有趣的语言,在VSCode中安装flutter插件后,就可以体验代码高亮、语法补全等功能了。如果使用Android Studio,还需要安装Dart插件,配置flutter的SDK路径等工作。

貌似Dart还可以编译成JavaScript的代码,这个后面再研究下~

2. 部件

widget 部件是每个Flutter应用程序的基本构建块,通过组合不同的 Widget,来实现我们用户交互界面,这跟Vue中的Components十分相似。

2.1. 无状态部件和有状态部件

widget分为两种

  • StatelessWidget,只用于展示信息,无用户交互行为
  • StatefulWidget,可以通过改变状态(数据)使得UI发生变化,可以包含用户交互

flutter的部件也是有生命周期的,大致生命周期可以分为

  • initState : 初始化widget的时候调用,只会调用一次。

  • build : 初始化之后开始绘制界面,当setState触发的时候会再次被调用

  • didUpdateWidget : 当触发setState时,会被调用

  • dispose : 页面销毁的时候调用

无状态部件和有状态部件的区别在于,StatelessWidget组件只会build绘制一次,而StatefulWidget主要状态发生改变,就会重新调用build方法,重新进行绘制。

2.2. 布局样式

Flutter中的布局样式与CSS中部分概念比较相似,如margin、padding、border等,尤其是CSS中的flex布局,在Flutter得到了有力的支持。

尽管概念比较相似,但是在flutter中为widget添加样式与CSS添加样式还是有很大区别的,我们知道伟大的W3C标准推荐“行为、样式、布局分离”,而在Flutter中

  • 不是所有 Widget 都可以添加任意的样式属性,有的部件只有布局样式,有的部件只有展示样式
  • 由于布局、样式和逻辑都一起书写到widget上,部件的嵌套可能就比较深~论两个空格缩进的重要性
  • 由于Dart语言的关系,基本上所有的样式属性都不在支持以字符串的形式书写,而是必须创建特定类的实例或是使用 Flutter 中预先定义好的常量

本文最后会整理在开发中常见的一些部件,用作备忘。

3. UI调试

做web开发已经习惯了使用Chrome的F12调试大法来进行界面调试,在Flutter中有什么比较好的UI调试方法呢?

3.1. Android的Flutter inspector

在Android Studio中,可以使用内置的Flutter inspector来实现布局调试。详情可参考Flutter Widget Inspecto-官方文档

如图所示,在模拟器打开flutter应用后,可以通过选择器选择对应的部件,然后就可以查看对应的部件名称和布局属性等。

此外可以通过rendering.dart包来调试布局,开启debugPaintSizeEnabled后可以在布局页面上看见很多箭头网格,了解大致的布局嵌套(虽然这个功能不太好用~)

import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;

void main(){
    debugPaintSizeEnabled = true;
    runApp(new MaterialApp(
        title: 'Fun',
        home: new FunApp()
    ));

}

3.2. iOS真机调试

首先参考官方文档进行安装,需要配置环境变量啥的,以及XCode。

brew update

brew install --HEAD libimobiledevice

brew install ideviceinstaller ios-deploy cocoapods

pod setup

然后进行下面流程:

  • 切换到项目目录,运行open ios/Runner.xcworkspace
  • 此时会打开xcode的runner,配置好开发证书,使用数据线连接iPhone真机
    • 如果弹出“要信任此电脑吗?”的弹框,请选择“信任”
  • 然后左上角,选择运行目标为Device->iPhone,点击运行,进行安装
  • 稍等片刻,就能在手机上看见安装的app了~
    • 个人账号需要在手机“设置”->“通用” -> “描述文件与设备管理”中信任开发者,然后才能打开程序

真机安装遇见的一个问题是: ListView滑动感觉比较卡顿

这个貌似是是因为安装的debug的缘故,安装release包就可以体验如丝般顺滑的体验。

flutter build ios --release

然后重新open ios/Runner.xcworkspace将release包安装在手机上即可。

3.3. Android真机

Android真机的安装要比iOS简单一点

  • 通过数据线连接电脑,windows貌似需要安装USB驱动
  • 手机开启“开发者模式”和“USB调试”选项
    • 提示“是否允许USB调试”,选择“是”

真机安装后,就可以愉快地使用啦~

4. 遇见的问题

下面整理在项目中遇见的一些问题

4.1. 包引入路径错误导致代码报错

import 'package:flutter_app/app/view//detail.dart';

上面面路径多写了一个/,导致无法调用正确的构造函数

No top-level method '' declared. Receiver: top-level,Tried calling: (12333)

这里原本调用的是

new TextDetailPage(12333)

但是奇怪的是调整该模块的构造函数,不传递参数,则又调用正常了

4.2. flutter命令被阻塞

在使用flutter doctor或者打包iOS真机包的时候遇见提示

Waiting for another flutter command to release the startup lock

在使用了flutter命令或者程序异常退出后,可能会出现这种提示,这时需要等待其他flutter命令执行完毕,或者手动删除<YOUR FLUTTER FOLDER>/bin/cache/lockfile文件

4.3. 本地图片资源加载失败

原来本地图片需要在pubsepc.yaml中进行声明

flutter:

  assets:

    - assets/img/ic_main_tab_company_pre.png

    - assets/img/ic_main_tab_my_pre.png

参考

* 在Flutter中添加资源和图片

### 解析JSON

解析json时报错

Unhandled exception: type 'List<dynamic>' is not a subtype of type 'List<JokeModel>'

static List<JokeModel> fromJson(String data) {

    // 这里还需要注意 dart:io包里面的json是小写了,之前找到有示例代码是JSON会提示undefined

    return json.decode(data)['data']

        .map((obj) => JokeModel.fromMap(obj))

        .toList();

}

这是因为默认map解析的List类型是List<dynamic>,解决办法是指定map类型

static List<JokeModel> fromJson(String data) {

    return json.decode(data)['data']

        .map<JokeModel>((obj) => JokeModel.fromMap(obj))

        .toList();

}

此外手写Model也是比较麻烦的事情,应该有根据json模板快速生成model文件的方法。

参考:

* issue#17008

5. 常见部件

这里整理了常见布局组件的一些属性值含义及使用方法,方便日后查询。

5.1. Container 容器

参考:Flutter Widgets: Container

相关属性

  • child,设置子组件
  • alignment,子组件在该Container中的对齐方式
  • constraints,约束,这个可以理解为css中的max-widthmax-height
  • transform,设置容器的矩阵变化,使用 Matrix4
  • 盒子模型,需要注意的是flutter内组件均与css中box-sizing:border-box类似,同样的宽度,增加内边距会导致子组件的宽度减小
    • width、height,设置容器的宽高
    • padding,设置内边距,使用EdgeInsets
    • margin,设置外边距
  • 背景
    • color,纯色背景
    • decoration,设置container的背景(如BoxDecoration),可以设置渐变啥的
    • foregroundDecoration,前景色,需要注意前景色是在child之后绘制的

5.2. Row和Column 行与列

参考:

Column和Row的用法十分相似,区别在于主轴方向不同。

相关属性

  • children,指定多个子元素
  • mainAxisAlignment,子元素主轴上的排列规则,类似于CSS的justify-content
  • crossAxisAlignment,子元素在纵轴上的对齐规则,类似于align-items
  • direction,指定主轴的方向

注意事项

  • 如果需要子元素可以扩张(类似于css中的flex:1属性),需要通过Expand组件包裹该子组件

5.3. Text 文本

参考:Flutter Widgets: Text

构造方法

new Text(data, options)
new Text.rich(new TextSpan)

相关属性

  • style,使用TextStyle类,里面的属性与CSS比较相似
    • inherit,是否继承字体样式
    • color,字体颜色
    • fontFamily,字体
    • fontSize,字体大小
    • fontWeight,字体粗细
    • fontStyle,正常(normal)或者倾斜(italic)
    • letterSpacing,字母间隙
    • wordSpacing,单词间隙
    • height,文本高度
    • locale,区域设置,这个就有点懵了
    • decoration,文本装饰,加个下划线、中划线啥的
    • decorationColor,文本装饰颜色
    • decorationStyle,文本装饰风格
  • textAlign,文字对齐方式,这个是文字换行时,多行文字时的对齐方式
  • textDirection,文本方向,只处理中英文一般不需要这个参数
  • softWrap,是否自动换行
  • overflow,文字超出屏幕时的处理方式,如截断、省略号、渐隐等
  • maxLinex,最大行数设置
  • TextSpan,在一个Text.rich中防止多个独立的文本

5.4. Image 图片

参考: Flutter Widgets: Image

构造方法

new Image(); // 需要实现ImageProvider 并制定image参数
new Image.asset(); // 资源图片
new Image.file(); // 本地图片
new Image.network(); // 网络图片 
new Image.memory(); // Uint8List图片

相关属性

  • width、height,图片容器的宽高
  • fit,源图片的填充规则,使用BoxFit对应属性
  • color、colorBlendMode,指定图片的混合模式,类似于css中的滤镜
  • repeat,当图片容器尺寸大于图片本身尺寸时的重复规则,类似于css中的background-repeat
  • centerSlice,定义图片的拉伸 类似于Android中点9图的拉伸位置
  • gaplessPlayback,图片资源ImageProvider变化时,在重新加载图片的过程中,原图片是否保留展示

5.5. TextField 文本输入框

参考:

相关属性

  • style,文本样式,同Text的style属性
  • dectoration,可以通过InputDecoration来添加一个标签、图标、提示文字和错误文本,placeholder也是在这里设置的
  • controller,文本编辑控制器TextEditingController的实例,可以用来获取用户输入
  • onChanged,监听输入框变化,也可以用来获取用户输入
  • maxLength,最大长度;maxLines,最大行数
  • obscureText,设置是否为密码类型
  • inputFormatters,输入类型的格式
  • onSubmitted,内容提交时的回调
记package-lock引发的一次事故 Chrome扩展程序之自动更新