你不得不了解的 Flutter 入门教程

火币集团技术研发中心是火币集团的一级部门, 主要负责7*24实时交易系统,实时风控系统,数字钱包,数据服务,大数据分析等系统的研发和系统维护工作,同时也为火币集团的全球生态事业群提供技术支持。我们致力于搭建全球领先的数字资产交易平台,提供逾两百对数字资产品类的交易及投资服务。同时研发中心也是区块链技术与基础设施的构建者,专注于区块链底层技术和应用场景相结合的研发,逐渐成为该领域的重要力量。

文章正文

enter image description here 图片来源: https://flutter.io

前言

Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作。在全世界,Flutter 正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

为什么要用 Flutter ?

  • 提高开发效率,同一份代码开发 iOS 和 Android,对于开发者可以轻松跨端开发,提升竞争力;

  • 受益于使用 Flutter 框架提供的丰富的 Material Design 和 Cupertino( iOS 风格)的 Widget,可以很轻松的在 iOS 平台上实现 Material 设计风格的用户体验;

  • 用更少的代码做更多的事情,通过丰富的属性设置,可以实现很炫的效果;

  • 在应用程序运行时更改代码并重新加载(HotReload),这个点真的是 App 开发质的提升;

  • 现代化的、响应式的框架、Redux、RxDart、BloC 等等框架可以帮助你逻辑和 UI 优雅的分离;

  • 轻松实现网络、异步、IO 等基础功能;

  • 国内阿里咸鱼、腾讯、京东、国外的谷歌等公司都已经有上线产品在使用 Flutter 开发,即使没有上线的也基本在上线的路上了。

Flutter 框架结构

enter image description here 图片来源: https://flutter.io

Flutter Framework

Framework 这一层使用 Dart 语言开发,它实现了一套基础库。

Foundation、Animation、Painting、Gestures 为 Dart 实现的 UI 层,提供动画、手势及绘制。

Rendering 渲染层,依赖 UI 层,在运行时 Rendering 层会构建一个 Widget 树,当有变化时,会更具一定的算法计算出有变化的部分,然后更新 Widget 树。

Widgets 层是 Flutter 提供的的一套基础组件库,在基础组件库之上,Flutter 还提供了 Material 和 Cupertino 两种视觉风格的组件库。

Flutter Engine

Skia 是个 2D 向量图形处理函数库,包含字型、坐标转换,以及点阵图都有高效能且简洁的表现。不仅用于 Google Chrome 浏览器,新兴的 Android 开放手机平台也采用 Skia 作为绘图处理,搭配 OpenGL/ES 与特定的硬件特征,强化显示的效果。

正式因为没有使用原声的 UI 和绘制框架,所以才保证了 Flutter 的高性能体验。

一切皆为 Widget

Widget 是 Flutter 应用程序用户界面的基本构建块,你能看到的和看不到的都是一个 Widget,可以分为以下几种类型:

  • 基础部件:Text、Image、Button、单选框、复选框、输入框、表单等;

  • 布局容器类:Wrap、Flow、Row、Column、Container、Stack 等;

  • 功能类:ListView,GridView,InheritedWidget 等。

开发工具

Flutter 提供响应式视图,无需任何 Javascript 桥接器与平台通信。Flutter 提供了大量的 Material Design 灵感组件,可以在应用程序中使用。

另外 IDE 推荐使用 Visual Studio Code,你可以下载安装 Flutter 插件,可以直接在编辑器选择真是设备或模拟器上调试和运行应用程序。Android Studio 或 IntelliJ 也都支持 Flutter 开发。

Dart 介绍

最初设计 Dart,是 Google 决定设计一个新语言用来替换 JavaScript 的,所以刚开始 Dart 也就是用来作为浏览器脚本运行在浏览器中的。为了推广 Dart,Google 利用自己的利器 Chrome 让它内置了 DartVM 的引擎。有了运行环境,加上用户群的可观数量,Dart 最初也赢得了部分前端开发者的青睐。

语言特性

  • 单进程异步事件模型;
  • 强类型,可以类型推断;
  • DartVM,具有极高的运行效率和优秀的代码运行优化,根据早前的基准测试,性能比肩 Java7 的 JVM;
  • 独特的隔离区( Isolate ),可以实现多线程;
  • 面向对象编程,一切数据类型均派生自 Object;
  • 运算符重载,泛型支持;
  • 强大的 Future 和 Stream 模型,可以简单实现高效的代码;
  • Minix 特性,可以更好的实现方法复用;
  • 全平台语言,可以很好的胜任移动和前后端的开发。
  • 在语法上,Dart 提供了很多便捷的操作,可以明显减少代码量。比如字符连接,可以直接 "my name is $name, age is $age",无需+号拼接,也无需做类型转换。

你可以直接进入 https://www.dartlang.org。open in dartpad,打开一个新页面,在不安装任何工具的情况下,编写 Dart 语言代码。

Dart 语言与其他语言一样都有一个 main 函数:

void main() {
    print ("hello dart");
}

Dart 语言的代码注释:

//单行注释
/*
  多行注释
*/

变量

使用 var 声明变量,无需指定具体类型。Dart 是强类型语言,在编译时贵根据第一次赋值判断并设置其类型,所以 var 变量一旦赋值,类型便确定,且不能在修改类型,只能修改其值。

var p;
p = "Hello Dart";
//这里会出现错误。
p = 1000;

Dynamic 和 Object

实际开发中确实可能会有类型转换的情景,所以 Dart 提供了 Dynamic 和 Object。

dynamic p;
p = "Hello Dart";
//这里没有问题。
p = 1000;

数据类型

  1. num 数字类型的父类,两个子类 int、double;

  2. String 使用单引号或者双引号创建字符串,单双引号可以嵌套。使用 ${} 可以加入其他变量拼接计算字符串;

  3. bool true 和 false;

  4. List 数组;
    • 定义List list = ['a','b','c'];
    • add 添加元素;
    • addAll 添加多个元素;
    • length 长度;
    • first 第一个元素,等同[0];
    • indexOf 定位某元素;
    • removeAt 移除某元素;
    • removeLast 移除最后一个元素;
    • clear 清除所有元素。
  5. Map 集合,类似OC中的 Dic,由键和值构成。

var iMap = new Map<int,String>();

异常

throw:

throw:抛出异常:throw new FormatException('this is a exception');

catch:

try {
    dosomething();
} on OutOfLlamasException {
    // A specific exception
    buyMoreLlamas();
} on Exception catch (e) {
    // Anything else that is an exception
    print('Unknown exception: $e');
} catch (e, s) {
    print('Exception details:\n $e');
    print('Stack trace:\n $s');
}        

rethrow

final foo = '';
void misbehave() {
    try {
      foo = "1";
    } catch (e) {
      print('2');
      rethrow;// 如果不重新抛出异常,main函数中的catch语句执行不到
    }
}
void main() {
    try {
      misbehave();
    } catch (e) {
      print('3');
    }
}

finally

final foo = '';
void misbehave() {
    try {
      foo = "1";
    } catch (e) {
      print('2');
    }
}

void main() {
    try {
      misbehave();
    } catch (e) {
      print('3');
    } finally {
      print('4'); // 即使没有rethrow最终都会执行到
    }
}

函数

在 Dart 中,函数也是对象。

  • 支持可选参数,使用{}
void action({bool flag,bool show}) {
    print('action');
}
  • 可选的位置参数,使用[]
String say(String from, String msg, [String device]) {
      var result = '$from says $msg';
      if (device != null) {
         result = '$result with a $device';
      }
      return result;
  }
  • 默认参数;
  • 函数参数,函数作为一个参数传递;
  • 函数变量,可以把一个函数赋值给变量;
  • 匿名函数,iOS block,函数指针概念相同;
  • 所有函数都有一个返回值,默认返回 null。

面向对象

  • Dart 是 OO(object-oriented)类型的语言,支持 mixin 的继承方式;
  • 创建一个对象,当然是用 new 和 constructor 一起。Dart 2 中可以省略 new;
  • 用.操作符来访问成员变量以及成员函数;
  • 没有设定初始值的实例变量为 null;
  • ?.来避免 null. 这个和 Kotlin、Swift 一样, 防 null 的;
  • 实例变量自动带 getter function. 如果这个实例变量没有用 final 定义, 也会自动生成 setter;
  • Dart 有简单的写构造函数的方法;
  • 如果没有命名构造函数, 那么 Dart 会帮我们创建一个空参的构造函数;
  • Named constructor 这个很有意思. 如果我们想有多个构造函数. 需要我们不同命名;
  • static const 类常量;
  • const 还可以创建常量值;
  • 初始化列表,除了调用父类的构造。

更多 Dart 语言的介绍移步官网

环境搭建

安装 Flutter

要安装和运行 Flutter,您的开发环境必须满足以下最低要求:

  • 操作系统:macOS(64位)
  • 磁盘空间:700 MB(不包括 IDE /工具的磁盘空间)。
  • 工具:Flutter 取决于您的环境中可用的这些命令行工具。 bash、mkdir、rm、git、curl、unzip、which
  • 下载:打开 https://flutter.io/docs/get-started/install,下载对应平台的 fluttermacosv1.0.0-stable.zip

enter image description here 图片来源:Flutter 官网

  • 解压:unzip ~/Downloads/fluttermacosv1.0.0-stable.zip
  • 将 flutter 工具添加到您的路径: export PATH=$PATH:pwd/flutter/bin

您现在可以运行 Flutter 命令了!

环境诊断

执行如下代码

flutter doctor

enter image description here

如果提示出现:! Doctor found issues in 1 category.则按详细提示内容安装对应的工具即可。

升级 Flutter

Flutter SDK 有多个分支,如 beta、dev、master,stable 。其中 stable 分支为稳定分支,dev 和 master 为开发分支,安装 flutter 后,你可以运行 flutter channel 查看所有分支。

带 "*" 号的分支即你本地的 Flutter SDK 跟踪的分支,要切换分支,可以使用 flutter channel beta 或 flutter channel master。

升级Flutter SDK:

flutter upgrade

获取项目所有的依赖包

flutter packages get。

获取项目所有依赖包的最新版本

flutter packages upgrade

更多命令行操作可以输入 flutter 回车查看。

工程目录

打开 VS Code 扩展面板,输入 flutter 点击安装。输入 Dart 点击安装。

enter image description here

创建 Flutter 项目

安装 Flutter 后,按下 cmd + shift + p,选择 Flutter:New Project,按提示创建 helloflutter 工程。 enter image description here

目录介绍

enter image description here

  1. Android、iOS 一看就明白吧,原生工程在这里,原生代码也在这里写;
  2. lib Flutter 代码在这里创建,类似 main.dart;
  3. test 单元测试,所有测试用例可以写这个目录下;
  4. pubspec.lock 类似 iOS 的 cocoapods,Android 的 Gradle,第三方库配置。

iOS 运行项目

enter image description here

  1. 首先使用 XCode 打开 iOS 目录下的 Runner.xcworkspace 工程文件,配置开发者账号、AppID 和证书等信息;
  2. 点击右下角设备列表,选择对应的设备,选择左边栏的‘调试’,绿色箭头启动调试;
  3. 启动模拟器:首先查看模拟器列表 'xcrun instruments -s',然后 ‘xcrun instruments -w "iPhone SE (12.1)"’,这样就可以启动 iPhone SE (12.1),然后在 VSCode 中就可以选择这个模拟器运行代码。

Android 运行项目

  1. 首先连接安卓设备,打开开发者调试开关;
  2. VSCode 选择对应的设备,然后 run 即可。

基础部件

Wideget 简介

Flutter Widget 采用现代响应式框架构建,这是从 React 中获得的灵感,中心思想是用 Widget 构建你的 UI。 Widget 描述了他们的视图在给定其当前配置和状态时应该看起来像什么。当 Widget 的状态发生变化时,Widget 会重新构建 UI,Flutter 会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。

Widget 与 Element

Widget 实际上就是 Element 的配置数据,Widget 树实际上是一个配置树,而真正的 UI 渲染树是由 Element 构成;不过,由于 Element 是通过 Widget 生成。

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  final Key key;

  @protected
  Element createElement();

  @override
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}
  • Widget 类继承自 DiagnosticableTree,DiagnosticableTree 即“诊断树”,主要作用是提供调试信息;
  • Key:这个 key 属性类似于 React/Vue 中的 key,主要的作用是决定是否在下一次 build 时复用旧的;
  • widget,决定的条件在 canUpdate() 方法中;
  • createElement():正如前文所述“一个 Widget 可以对应多个 Element”;Flutter Framework 在构建 UI 树时,会先调用此方法生成对应节点的 Element 对象。此方法是 Flutter Framework 隐式调用的,在我们开发过程中基本不会调用到;
  • debugFillProperties(...) 复写父类的方法,主要是设置诊断树的一些特性;
  • canUpdate(...)是一个静态方法,它主要用于在 Widget 树重新 build 时复用旧的 widget,其实具体来说,应该是:是否用新的 Widget 对象去更新旧UI树上所对应的 Element 对象的配置;通过其源码我们可以看到,只要 newWidget 与 oldWidget 的 runtimeType 和 key 同时相等时就会用 newWidget 去更新 Element 对象的配置,否则就会创建新的 Element。

Widget 类本身是一个抽象类,其中最核心的就是定义了 createElement() 接口,在 Flutter 开发中,我们一般都不用直接继承 Widget 类来实现 Widget,相反,我们通常会通过继承 StatelessWidget 和 StatefulWidget 来间接继承 Widget 类来实现,而 StatelessWidget 和 StatefulWidget 都是直接继承自 Widget 类。

Stateless Widget

StatelessWidget 用于不需要维护状态的场景,它通常在 build 方法中通过嵌套其它 Widget 来构建 UI,在构建过程中会递归的构建其嵌套的 Widget。

class Page extends StatelessWidget {
  final String title;

  Page({Key key,this.title,});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
     appBar: AppBar(
       title: Text(title),
     ),
      body: Container(
        child:Text(title),
        color: Colors.yellow,
     
                        
作者正在撰写中...
隐藏内容 支付可见
内容互动
写评论
加载更多
评论文章
¥1.99 购买
× 订阅 Java 精选频道
¥ 元/月
订阅即可免费阅读所有精选内容