Flutter

  • Flutter是谷歌公司开发的一款开源、免费的移动UI框架,可以让我们快速的在Androidios上构建高质量App。它最大的特点就是跨平台、以及高性能
  • 官方文档:https://flutter.dev/

环境搭建

  • 参考技术胖Flutter免费视频第一季-环境搭建:https://jspang.com/detailed?id=41#toc21
  • 首先需要配置Java JDK,然后安装android studio,官方网站:https://developer.android.google.cn/studio/
  • 配置Android sdk路径的时候不能有中文和空格
  • 再在Flutter官网下载Flutter SDK,下载好后解压到一个路径,配置好环境变量,把bin目录复制到Path
  • 使用flutter -v命令检查是否配置成功
  • 搭建环境过程中要下载很多资源文件,当一些资源下载不了的时候,可能会报各种错误。在国内访问Flutter的时候有可能会受到限制。Flutter官方为我们提供了国内的镜像:https://flutterchina.club/setup-windows/
1
2
3
# 把下面两个添加到环境变量里,键值对
PUB_HOSTED_URL=https://pub.flutter-io.cn
FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
  • 使用flutter doctor 命令可以检查是否配置成功,出现cmdline-tools component is missing,参考博客

  • 如果找不到Android SDK,就运行以下命令

1
lutter config --android-sdk D:\AndroidSDK
  • 汉化:进入https://plugins.jetbrains.com/,找个中文插件,下载203.xxx版本的语言包,然后在Android studio中从本地磁盘安装插件即可

安装虚拟机

  • 虚拟机配置好后,使用debug启动项目,启动过程会有点慢,耐心等待,建议修改android目录下的build.gradle文件,把google()jcenter()这两行去掉,改为阿里的链接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://download.flutter.io'}
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public'}
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://download.flutter.io'}
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public'}
google()
mavenCentral()
}
}

rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
delete rootProject.buildDir
}
  • 再修改Flutter SDK包下的flutter.gradle文件,这个目录要根据你的SDK存放的位置有所变化,比如
1
D:\FlutterSDK\flutter_windows_2.8.1-stable\flutter\packages\flutter_tools\gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://download.flutter.io'}
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public'}
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
}
}

VsCode配置

  • Android Studio进行开发的,感觉太重量级了,所以比较喜欢使用VsCode进行配置
  • VsCode中只需要安装FlutterDart插件即可。关于虚拟机,可以制作一个批处理文件,来直接开启AVD虚拟机,这样就不用再等两分钟来开启Android Studio了
    • 在桌面新建EmulatorRun.bat文件 ,名字可以自定义
    • 查找emulator.exe文件的路径,把查找到的路径放到bat文件中,推荐使用Everything软件查找
    • 一般会查找到两个emulator.exe文件,一个是在tools目录下,一个是在emulator目录下,我们选择emulator目录下的这个,复制它的路径
1
D:\AndroidSDK\emulator\emulator.exe
  • 然后打开Android Studio,并查看你的AVD虚拟机名称,空格使用_代替,然后加在新建的bat文件中,然后双击bat文件就可以打开虚拟机
    • netdelay none :设置模拟器的网络延迟时间,默认为none,就是没有延迟
    • netspeed full:设置网络加速值,full代表全速
1
D:\AndroidSDK\emulator\emulator.exe -netdelay none -netspeed full -avd Pixel_5_API_30
  • 现在模拟器也有了,VSCode也支持Flutter开发了,在VsCode中ctrl+~打开终端,然后在终端中输入下面的命令,经过短暂的编译后就会启动我们的程序了
1
2
# 前提开启了虚拟机
flutter run
  • 如果频繁打开bat文件比较麻烦,在安装了Flutter和Dart插件以后,在VSCode的右下角显示No Devices,我们直接点击它,就会显示我们电脑中安装的虚拟机,如果你电脑上没有,也可以进行安装

入口文件

  • VsCode创建Flutter项目
1
flutter create xxx
  • lib/main.dart为项目的入口文件,可以在里面编写代码
  • StatefulWidget : 具有可变状态的窗口部件,也就是你在使用应用的时候就可以随时变化,比如我们常见的进度条,随着进度不断变化。
  • StatelessWidget:不可变状态窗口部件,也就是你在使用时不可以改变,比如固定的文字(写上后就在那里了,死也不会变了)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 引入UI库
import 'package:flutter/material.dart';
//主函数(入口函数) 箭头函数
void main() =>runApp(MyApp());
// 声明MyApp类
class MyApp extends StatelessWidget{
//重写build方法
@override
Widget build(BuildContext context){
//返回一个Material风格的组件
return MaterialApp(
title:'Welcome to Flutteraa',
home:Scaffold(
//创建一个Bar,并添加文本
appBar:AppBar(
title:Text('Welcome to Flutter'),
),
//在主体的中间区域,添加一个hello world 的文本
body:Center(
child:Text('Hello World'),
),
),
);
}
}
  • 写完后打开终端,运行flutter run,等待一小会,就会看到虚拟机中显示了Hello World的内容
  • VsCode编写唯一不好的就是无法热更新,需要在终端按以下按键
1
2
3
4
r 键:点击后热加载,也就算是重新加载吧。
p 键:显示网格,这个可以很好的掌握布局情况,工作中很有用。
o 键:切换android和ios的预览模式。
q 键:退出调试预览模式。
  • 另一种方法就是启用debug模式,保存就能产生变化

Widget

StatelessWidget

  • 无状态组件 StatelessWidget,是不可变的,这意味着它们的属性不能改变,所有的值都是最终的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {

@override
Widget build(BuildContext context) {
return MaterialApp(
// 去掉右上角debug
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}

class HomePage extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter_Demo'),
elevation: 10.0, // 阴影
centerTitle: true, // 居中
),
);
}
}

  • 无状态组件传递参数方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Test",
home: Scaffold(
appBar: AppBar(
title: Text("Test"),
),
body: MyText(
str1: "传递的值", //向自定义的MyText类传值,格式:参数名称:参数值
),
),
);
}
}

class MyText extends StatelessWidget {
const MyText({Key key,@required this.str1}) : super(key: key); //接收传递过来的值,使用@required修饰,表示为必传参数
final String str1; //定义接收参数

@override
Widget build(BuildContext context) {
return Text(str1);
}
}

StatefulWidget

  • 有状态组件StatefulWidget持有状态可能在Widget生命周期中发生变化。实现一个StatefulWidget至少需要两个类
    • 一个StatefulWidget
    • 一个State类。StatefulWidget类本身是不变的,但是State类在Widget生命周期中始终存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {

@override
Widget build(BuildContext context) {
return MaterialApp(
// 去掉右上角debug
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}

class HomePage extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter_Demo'),
elevation: 10.0, // 阴影
centerTitle: true, // 居中
),
body: CountPage(),
);
}
}

// stf 有状态
class CountPage extends StatefulWidget {

@override
_CountPageState createState() => _CountPageState();
}

class _CountPageState extends State<CountPage> {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children:[
Text('$count'),
RaisedButton(onPressed: (){
setState(() {
count++;
});
},child: Text("点击"))
]
);
}
}
  • 有状态组件传递参数方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Test",
home: Scaffold(
appBar: AppBar(
title: Text("Test"),
),
body: MyText(
str1: "传递的值", //向自定义的MyText类传值,格式:参数名称:参数值
),
),
);
}
}

class MyText extends StatelessWidget {
const MyText({Key key,@required this.str1}) : super(key: key); //接收传递过来的值,使用@required修饰,表示为必传参数
final String str1; //定义接收参数

@override
Widget build(BuildContext context) {
// 有状态的参数都在widget里面,整型要使用toString()转一下
return Text(widget.str);
}
}