Flutter入门:第一个Flutter应用

Posted by alonealice on 2020-12-28

创建应用

  1. 打开 IDE,选择 新 Flutter 项目 (Start a new Flutter project).
  2. 选择 Flutter 应用程序 作为项目类型,然后点 下一步
  3. 确认 Flutter SDK 路径 区域所示路径是正确的 SDK 路径。如果你还没有安装 SDK,需要先进行安装,选择 Install SDK…
  4. 输入项目名称(比如 ‘myapp’), 然后点击下一步
  5. 点击 完成
  6. 待 Android Studio 安装 SDK 后,创建项目。

APP代码结构

1
2
3
4
5
firstApp
├── android
├── ios
├── lib
└── test

其中android里面的就是生成的android相关的文件,而ios里面是生成的ios相关的文件,lib中则是flutter的dark文件。如果需要添加其他的文件,则一般会直接在根目录下添加,比如我们需要使用外部图片和Icon资源,所以我们在项目根目录下分别创建“imgs”和“fonts”文件夹。

第一个页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Hello World'),
),
),
);
}
}
  • 本示例创建了一个具有 Material Design 风格的应用, Material 是一种移动端和网页端通用的视觉设计语言, Flutter 提供了丰富的 Material 风格的 widgets。在 pubspec.yaml 文件的 flutter 部分选择加入 uses-material-design: true 会是一个明智之举,通过这个可以让您使用更多 Material 的特性,比如其预定义好的 图标 集。
  • 主函数(main)使用了 (=>) 符号,这是 Dart 中单行函数或方法的简写。
  • 该应用程序继承了 StatelessWidget,这将会使应用本身也成为一个 widget。在 Flutter 中,几乎所有都是 widget,包括对齐 (alignment)、填充 (padding) 和布局 (layout)。
  • Scaffold 是 Material 库中提供的一个 widget,它提供了默认的导航栏、标题和包含主屏幕 widget 树的 body 属性。 widget 树可以很复杂。
  • 一个 widget 的主要工作是提供一个 build() 方法来描述如何根据其他较低级别的 widgets 来显示自己。
  • 本示例中的 body 的 widget 树中包含了一个 Center widget, Center widget 又包含一个 Text 子 widget, Center widget 可以将其子 widget 树对齐到屏幕中心。

使用外部 package

pubspec.yaml 文件管理 Flutter 应用程序的 assets(资源,如图片、package等)。在pubspec.yaml 中,将 english_words(3.1.5 或更高版本)添加到依赖项列表

1
2
3
4
5
dependencies:
flutter:
sdk: flutter
english_words: ^3.1.5
cupertino_icons: ^1.0.0

同时点击Pub get 会将依赖包安装到你的项目。

lib/main.dart 中引入:

1
2
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

使用并替换文本内容

1
2
3
4
5
6
7
8
9
10
11
12
final wordPair = WordPair.random();
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text(wordPair.asCamelCase),
),
),
);

在现有工程中添加Flutter

Dark语言简介

变量

var:类似于JavaScript中的var,它可以接收任何类型的变量,但最大的不同是Dart中var变量一旦赋值,类型便会确定,则不能再改变其类型。

dynamicObjectObject 是Dart所有对象的根基类。任何类型的数据都可以赋值给Object声明的对象。dynamic和**Object **声明的变量可以在后期改变赋值类型。

dynamicObject不同的是,dynamic声明的对象编译器会提供所有可能的组合, 而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dynamic a;
Object b;
main() {
a = "";
b = "";
printLengths();
}

printLengths() {
// no warning
print(a.length);
// warning:
// The getter 'length' is not defined for the class 'Object'
print(b.length);
}

finalconst:如果您从未打算更改一个变量,那么使用 finalconst,不是var,也不是一个类型。 一个 final 变量只能被设置一次,两者区别在于:const 变量是一个编译时常量,final变量在第一次使用时被初始化。

函数

函数可以赋值给变量或作为参数传递给其他函数

函数声明:

1
2
3
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}

对于只包含一个表达式的函数,可以使用简写:

1
bool isNoble (int atomicNumber)=> _nobleGases [ atomicNumber ] != null ;

函数作为变量:

1
2
3
4
var say = (str){
print(str);
};
say("hi world")

函数作为参数传递:

1
2
3
4
void execute(var callback) {
callback();
}
execute(() => print("xxx"))

可选的位置参数

包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面:

1
2
3
4
5
6
7
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}

可选的命名参数

定义函数时,使用{param1, param2, …},放在参数列表的最后面,用于指定命名参数

1
2
3
4
5
void enableFlags({bool bold, bool hidden}) {
// ...
}

enableFlags(bold: true, hidden: false);

异步

Future或者Stream对象的函数,被称为异步函数asyncawait关键词支持了异步编程,允许您写出和同步代码很像的异步代码。

Future

表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。

Future.thenFuture.delayed 创建了一个延时任务

1
2
3
4
5
Future.delayed(new Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});

Future.catchError:如果异步任务发生错误,我们可以在catchError中捕获错误

1
2
3
4
5
6
7
8
9
10
Future.delayed(new Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print("success");
}).catchError((e){
//执行失败会走到这里
print(e);
});

then方法还有一个可选参数onError,我们也可以它来捕获异常:

1
2
3
4
5
6
7
8
Future.delayed(new Duration(seconds: 2), () {
//return "hi world!";
throw AssertionError("Error");
}).then((data) {
print("success");
}, onError: (e) {
print(e);
});

Future.whenComplete:我们会遇到无论异步任务执行成功或失败都需要做一些事的场景,可以使用FuturewhenComplete回调

1
2
3
4
5
6
7
8
9
10
11
12
Future.delayed(new Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});

Future.wait:需要等待多个异步任务都执行结束后才进行一些操作,就可以使用wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Future.wait([
// 2秒后返回结果
Future.delayed(new Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回结果
Future.delayed(new Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});

4s后才会打印

Async/await

和JavaScript中的async/await功能和用法是一模一样的。

  • async用来表示函数是异步的,定义的函数会返回一个Future对象,可以使用then方法添加回调函数。
  • await 后面是一个Future,表示等待该异步任务完成,异步完成后才会往下走;await必须出现在 async 函数内部。
1
2
3
4
5
6
7
8
9
10
11
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}
Stream

Stream 也是用于接收异步事件数据,和Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(new Duration(seconds: 1), () {
return "hello 1";
}),
// 抛出一个异常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回结果
Future.delayed(new Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){

});