前言:距离上次写Flutter已经2个月过去了,这两天打开Flutter项目一看,既有些熟悉又有些陌生。由于目前的项目是用Swift写的,项目有点小忙。忙只是接口,保持持续的输入输出才是重中之重。要是丢了Flutter这块的知识储备,觉得实在是太可惜,于是决定重新开启启程之路。早上提前到办公室学习半小时,中午再利用中午空挡时间学习半小时。 这样光工作的闲鱼时间一个月算下来110个小时。。
Let's learn together!
一、创建工程
二、开始Flutter代码
2.1 Hello World的实现
2.2 代码分析
2.2.1 runApp和Widget
2.2.2. Material设计风格
2.3 代码优化
2.3.1 改进界面样式及结构
2.4 代码重构
2.4.1. 创建自己的Widget
2.4.2. StatelessWidget
2.4.3. 重构案例代码
一、创建工程
创建功能之后会有一些默认的代码,直接运行,我们会发现这是一个计数器的案例程序,点击右下角的 + 符号,上面显示的数字会递增;
默认项目分析:
在目录下有一个lib文件夹,里面会存放我们编写的Flutter代码;
打开发现里面有一个main.dart,它是我们Flutter启动的入口文件,里面有main函数;
我们第一次接触main.dart中的代码,可能会发现很多不认识的代码,不知道这个内容是如何编写出来的;
作为初学者,我的建议是将其中所有的代码全部删除掉,从零去创建里面的代码,这样我们才能对Flutter应用程序的结构非常清晰;
二、开始Flutter代码
2.1 Hello World的需求实现(简单粗暴型实现方式)
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(Text("Hello World", textDirection: TextDirection.ltr));
}
疑惑
- 导入的Material是什么呢?
- 我们在main函数中调用了一个runApp()函数又是什么呢?
2.2 代码分析
2.2.1 runApp和Widget
runApp是Flutter内部提供的一个函数,当我们启动一个Flutter应用程序时就是从调用这个函数开始的
我们可以点到runApp的源码,查看到该函数
void runApp(Widget app) {
...省略代码
}
该函数让我们传入一个东西:Widget?
对Widget的理解:
- 做过Android、iOS等开发的人群,喜欢将它翻译成控件;
- 做过Vue、React等开发的人群,喜欢将它翻译成组件;
- 如果我们使用Google,Widget翻译过来应该是小部件;
Widget到底什么东西呢?
我们学习Flutter,从一开始就可以有一个基本的认识:Flutter中万物皆Widget(万物皆可盘);
在我们iOS或者Android开发中,我们的界面有很多种类的划分:应用(Application)、视图控制器(View Controller)、活动(Activity)、View(视图)、Button(按钮)等等;
但是在Flutter中,这些东西都是不同的Widget而已;
也就是我们整个应用程序中所看到的内容几乎都是Widget,甚至是内边距的设置,我们也需要使用一个叫Padding的Widget来做;
runApp函数让我们传入的就是一个Widget:
但是我们现在没有Widget,怎么办呢?
我们可以导入Flutter默认已经给我们提供的Material库,来使用其中的很多内置Widget;
2.2.2. Material设计风格
material是什么呢?
material是Google公司推行的一套设计风格,或者叫设计语言、设计规范等;
里面有非常多的设计规范,比如颜色、文字的排版、响应动画与过度、填充等等;
在Flutter中高度集成了Material风格的Widget;
在我们的应用中,我们可以直接使用这些Widget来创建我们的应用(后面会用到很多);
Text小部件分析:
我们可以使用Text小部件来完成文字的显示;
我们发现Text小部件继承自StatelessWidget,StatelessWidget继承自Widget;
所以我们可以将Text小部件传入到runApp函数中
属性非常多,但是我们已经学习了Dart语法,所以你会发现只有this.data属性是必须传入的。
2.3 代码优化
需求改进:
- 我们可能希望文字居中显示,并且可以大一些;
- 居中显示: 需要使用另外一个Widget,Center;
- 文字大一些: 需要给Text文本设置一些样式;
2.3.1 改进界面样式及结构
正常的App页面应该有一定的结构,比如通常都会有导航栏,会有一些背景颜色等
在开发当中,我们并不需要从零去搭建这种结构化的界面,我们可以使用Material库,直接使用其中的一些封装好的组件来完成一些结构的搭建
import 'package:flutter/material.dart';
main(){
runApp(
MaterialApp(
debugShowCheckedModeBanner:false ,
home: Scaffold(
appBar: AppBar(
title: Text("Flutter"),
),
body: Center(
child: Text(
"Hello World",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 20),
),
),
),
),
);
}
代码解读
在最外层包裹一个MaterialApp
这意味着整个应用我们都会采用MaterialApp风格的一些东西,方便我们对应用的设计,并且目前我们使用了其中两个属性;
title:这个是定义在Android系统中打开多任务切换窗口时显示的标题;(暂时可以不写)
home:是该应用启动时显示的页面,我们传入了一个Scaffold;
Scaffold是什么呢?
翻译过来是脚手架,脚手架的作用就是搭建页面的基本结构;
所以我们给MaterialApp的home属性传入了一个Scaffold对象,作为启动显示的Widget;
Scaffold也有一些属性,比如appBar和body;
appBar是用于设计导航栏的,我们传入了一个title属性;
body是页面的内容部分,我们传入了之前已经创建好的Center中包裹的一个Text的Widget;
2.4 代码重构
2.4.1 创建自己的Widget
当代码嵌套过多时,结构很容易看不清晰。学会拆分以及抽取使其代码可读性更高,乃是重中之重!!!
2.4.2 StatelessWidget
StatelessWidget通常是一些没有状态(State,也可以理解成data)需要维护的Widget:
它们的数据通常是直接写死;
从parent widget中传入的而且一旦传入就不可以修改;
我们来看一下创建一个StatelessWidget的格式:
1、让自己创建的Widget继承自StatelessWidget;
2、StatelessWidget包含一个必须重写的方法:build方法;
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return <返回我们的Widget要渲染的Widget,比如一个Text Widget>;
}
}
build方法的解析:
Flutter在拿到我们自己创建的StatelessWidget时,就会执行它的build方法;
我们需要在build方法中告诉Flutter,我们的Widget希望渲染什么元素,比如一个Text Widget;
StatelessWidget没办法主动去执行build方法,当我们使用的数据发生改变时,build方法会被重新执行;
build方法什么情况下被执行呢?:
1、当我们的StatelessWidget第一次被插入到Widget树中时(也就是第一次被创建时);
2、当我们的父Widget(parent widget)发生改变时,子Widget会被重新构建;
3、如果我们的Widget依赖InheritedWidget的一些数据,InheritedWidget数据发生改变时;
2.4.3 重构案例代码
- 整个代码都是一些数据展示,没有数据的改变,使用StatelessWidget即可
- 为了体现更好的封装性,对代码进行了两层的拆分,让代码结构看起来更加清晰
重构后的代码如下:
import 'package:flutter/material.dart';
//只有一行代码 可用箭头函数
main() =>( runApp(MyApp()));
/*
* Widget:
* 有状态的Widget:StatefulWidget 在运行过程中有些状态(data)需要改变
* 无状态的Widget:StatelessWidget 内容是确定灭有状态(data)的改变
* */
//写死的东西则选用StatelessWidget继承
class MyApp extends StatelessWidget{
//StatelessWidget中的 有个抽象方法 build 必须要实现
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner:false ,
home: Scaffold(
appBar: AppBar(
title:Text("Flutter"),
),
body: HomeBody(),
),
);
}
}
class HomeBody extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Center(
child: Text("Hello World",
style: TextStyle(
color: Colors.red,
fontSize:32.0,
)
),
);
}
}