六、Flutter之开发初体验

一. 创建Flutter项目

创建Flutter项目有两种方式:通过命令行创建 和 通过开发工具创建

1.1. 通过命令行创建

通过命令行创建非常简单,在终端输入命令即可:flutter create learn_flutter

注意:Flutter的名称不要包含特殊的字符,另外不可以使用驼峰标识

创建完之后使用自己喜欢的开发工具打开即可

1.2. 通过开发工具创建

我这里也可以直接通过Android Studio来进行创建:

选择Start a new Flutter project,之后填写相关的信息即可,这里不再赘述

默认项目分析:

我们之前已经分析过目录结构了,在目录下有一个lib文件夹,里面会存放我们编写的Flutter代码;

打开发现里面有一个main.dart,它是我们Flutter启动的入口文件,里面有main函数;

二. 开始Flutter代码

2.1. Hello World

2.1.1. Hello World的需求

做任何的开发,我们都是从祖传的Hello World开始,那么现在我们的需求来了:在界面中心位置,显示一个Hello World;

2.1.2. Hello World的实现

下面,我们就动手开始编写Hello World:

我们知道Dart程序的入口都是main函数,而Flutter是Dart编写的,所以入口也是main函数;

但是我们导入的Material是什么呢?另外,我们在main函数中调用了一个runApp()函数又是什么呢?

下面,我们对不认识的代码进行一些分析。

2.2. 代码分析

2.2.1. runApp和Widget

runApp是Flutter内部提供的一个函数,当我们启动一个Flutter应用程序时就是从调用这个函数开始的

我们可以点到runApp的源码,查看到该函数

void runApp(Widget app) { 

 ...省略代码

}

该函数让我们传入一个东西:Widget

我们先说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属性是必须传入的。

StatelessWidget简单介绍:

StatelessWidget继承自Widget;

后面我会更加详细的介绍它的用法;

abstract class StatelessWidget extends Widget {

// ...省略代码

}

2.3. 代码改进

2.3.1. 改进界面样式

我们发现现在的代码并不是我们想要的最终结果:

我们可能希望文字居中显示,并且可以大一些;

居中显示: 需要使用另外一个Widget,Center;

文字大一些: 需要给Text文本设置一些样式;

我们修改代码如下:

我们在Text小部件外层包装了一个Center部件,让Text作为其child;

并且,我们给Text组件设置了一个属性:style,对应的值是TextStyle类型;

2.3.2. 改进界面结构

目前我们虽然可以显示HelloWorld,但是我们发现最底部的背景是黑色,并且我们的页面并不够结构化。正常的App页面应该有一定的结构,比如通常都会有导航栏,会有一些背景颜色等

在开发当中,我们并不需要从零去搭建这种结构化的界面,我们可以使用Material库,直接使用其中的一些封装好的组件来完成一些结构的搭建。

我们通过下面的代码来实现

在最外层包裹一个MaterialApp

这意味着整个应用我们都会采用MaterialApp风格的一些东西,方便我们对应用的设计,并且目前我们使用了其中两个属性;

title:这个是定义在Android系统中打开多任务切换窗口时显示的标题;(暂时可以不写)

home:是该应用启动时显示的页面,我们传入了一个Scaffold;

Scaffold是什么呢?

翻译过来是脚手架,脚手架的作用就是搭建页面的基本结构;

所以我们给MaterialApp的home属性传入了一个Scaffold对象,作为启动显示的Widget;

Scaffold也有一些属性,比如appBar和body;

appBar是用于设计导航栏的,我们传入了一个title属性;

body是页面的内容部分,我们传入了之前已经创建好的Center中包裹的一个Text的Widget;

2.3.3. 进阶案例实现

我们可以让界面中存在更多的元素:写到这里的时候,你可能已经发现嵌套太多了,不要着急,我们后面会对代码重构的

2.4. 代码重构

2.4.1. 创建自己的Widget

很多学习Flutter的人,都会被Flutter的嵌套劝退,当代码嵌套过多时,结构很容易看不清晰。

这里有两点我先说明一下:

1、Flutter整个开发过程中就是形成一个Widget树,所以形成嵌套是很正常的。

2、关于Flutter的代码缩进,更多开发中我们使用的是2个空格(前端开发2个空格居多,你喜欢4个也没问题)

但是,我们开发一个这么简单的程序就出现如此多的嵌套,如果应用程序更复杂呢?

我们可以对我们的代码进行封装,将它们封装到自己的Widget中,创建自己的Widget;

如何创建自己的Widget呢?

在Flutter开发中,我们可以继承自StatelessWidget或者StatefulWidget来创建自己的Widget类;

StatelessWidget: 没有状态改变的Widget,通常这种Widget仅仅是做一些展示工作而已;

StatefulWidget: 需要保存状态,并且可能出现状态改变的Widget;

在上面的案例中对代码的重构,我们使用StatelessWidget即可,所以我们接下来学习一下如果利用StatelessWidget来对我们的代码进行重构;

2.4.2. StatelessWidget

StatelessWidget通常是一些没有状态(State,也可以理解成data)需要维护的Widget:

它们的数据通常是直接写死(放在Widget中的数据,必须被定义为final,为什么呢?我在下一个章节讲解StatefulWidget会讲到);

从parent widget中传入的而且一旦传入就不可以修改;

从InheritedWidget获取来使用的数据(这个放到后面会讲解);

我们来看一下创建一个StatelessWidget的格式:

1、让自己创建的Widget继承自StatelessWidget;

2、StatelessWidget包含一个必须重写的方法:build方法;

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来对我们的代码进行重构了。因为我们的整个代码都是一些数据展示,没有数据的改变,使用StatelessWidget即可;

另外,为了体现更好的封装性,我对代码进行了两层的拆分,让代码结构看起来更加清晰;

重构后的代码如下:

三. 案例练习

3.1. 自定义Widget

在我们的案例中,很明显一个产品的展示就是一个大的Widget,这个Widget包含如下Widget:

标题的Widget:使用一个Text Widget完成;

描述的Widget:使用一个Text Widget完成;

图片的Widget:使用一个Image Widget完成;

上面三个Widget要垂直排列,我们可以使用一个Column的Widget(上一个章节中我们使用了一次Row是水平排列的)

另外,三个展示的标题、描述、图片都是不一样的,所以我们可以让Parent Widget来决定内容:

创建三个成员变量保存父Widget传入的数据

3.3. 列表数据展示

现在我们就可以创建三个ProductItem来让他们展示了:

MyApp和上一个章节是一致的,没有任何改变;

HomeContent中,我们使用了一个Column,因为我们创建的三个ProductItem是垂直排列的

运行效果如下:

错误信息:出现了黄色的斑马线;这是因为在Flutter的布局中,内容是不能超出屏幕范围的,当超出时不会自动变成滚动效果,而是会报错误;

如何可以解决这个问题呢?

我们将Column换成ListView即可;ListView可以让自己的子Widget变成滚动的效果;

3.4. 案例细节调整

3.4.1. 界面整体边距

如果我们希望整个内容距离屏幕的边缘有一定的间距,怎么做呢?

我们需要使用另外一个Widget:Padding,它有一个padding属性用于设置边距大小;

3.4.2. 商品内边距和边框

我们现在希望给所有的商品也添加一个内边距,并且还有边框,怎么做呢?

我们可以使用一个Container的Widget,它里面有padding属性,并且可以通过decoration来设置边框;

3.4.3. 文字图片的间距

我们希望给图片和文字之间添加一些间距,怎么做呢?

方式一:给图片或者文字添加一个向上的内边距或者向下的内边距;

方式二:使用SizedBox的Widget,设置一个height属性,可以增加一些距离;

3.5. 最终实现代码

最后,我给出最终实现代码:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容