2019-09-26: 十二:正式Flutter项目创建

十二:正式Flutter项目创建

作者 主题
lishengbing 正式Flutter项目创建

一: 创建Flutter项目

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

1.1: 通过命令行创建

在终端输入命令:flutter create helloworld 即可

  • flutter的名称不要包含特殊的字符、另外不可以使用驼峰标识。
  • 创建完之后使用自己喜欢的开发工具打开即可。

2: 通过开发工具创建

我这里也可以使用Android Studio来进行创建

  • 选择Star a new Flutter project


    图片.png

1.3: 默认程序分析

默认程序分析:
  • 我们之前已经分析过目录结构了、在目录下有一个lib文件夹、里面会存放我们编写的Flutter代码。
  • 打开发现里面有一个main.dart、它是我们Flutter启动的入口文件、里面有main函数;
默认代码分析:
  • 这是一个计数器的案例程序、点击右下角+符号、上面显示的数字会递增;
  • 但是我们第一次接触main.dart中的代码、可能会发现很多不认识的代码、作为初学者、建议将其中所有的代码都删除掉、从零去创建里面的代码、这样我们才能对Flutter应用程序的结果非常清晰。

二: 开始Flutter代码

2.1.1: HelloWorld 需求: 在界面中心显示一个helloWorld

2.1.2: HelloWorld代码实现

import 'package:flutter/material.dart';
main(List<String> args) {
  runApp(Text("hello world", textDirection: TextDirection.ltr));
}

通过上面的代码已经实现了在界面上显示HelloWorld

  • 但是没有居中、字体也有点小
    上面的代码我们有一些比较熟悉、有一些是不清楚是什么:
  • 比如我们知道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、甚至是内边距的设置、我们也需要使用一个叫Paddig的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:
  • 后续会详细介绍它的用法:

2.3: 代码改进

2.3.1: 改进界面样式

  • 居中显示、需要使用另外一个Widget, Center
  • 文字大一些: 需要给Text文本设置一些样式
    代码如下:
runApp(
    Center(
      child: Text(
        'hello world',
        textDirection: TextDirection.ltr,
        style: TextStyle(fontSize: 36),
      ),
    )
  );
图片.png

2.3.1: 改进界面机构

目前我们虽然可以显示HelloWorld、但是我们发现最底部的背景是黑色、并且我们的页面并不能结构化

  • 正常的App页面应该有一定的机构、比如通常会有导航栏、会有一些背景颜色等。
    在开发当中、我们并不需要从零去搭建这种结构化界面、我们可以使用material库、直接使用其中的一些封装好的组件来完成一些结构化的搭建
    我们通过以下的代码来实现:
runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('lishengbing'),
        ),
        body: Center(
          child: Text(
            'hello world',
            textDirection: TextDirection.ltr,
            style: TextStyle(fontSize: 38),
          ),
        ),
      ),
    )

  );

效果如图


图片.png

在最外层包装了一个MaterialApp

  • 这意味着整个应用我们都会采用MaterialApp风格的一些东西、方便我们对应用的设计、并且目前我们使用了其中两个属性。
    title: 这个是定义在Android系统中打开多任务窗口时显示的标题、暂时可以不写
  • home: 是该应用启动时显示的页面、我们传入一个Scaffold;
scaffold是什么呢?
  • 翻译过来是脚手架、脚手架的作用就是搭建页面的基本结构;
  • 所以我们给MaterialApp的home属性传入了一个scaffold对象、作为启动显示的Widget。
  • Scaffold也有一些属性、比如appBar和body;
    • appBar:是用于设计导航栏的、我们传入了一个title属性;
    • body: 是页面的内容部分、我们传入了之前已经创建好的Ceter中包裹的一个Text的Widget;

2.3.3: 进阶案例实现

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

runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('首页'),
        ),
        body: Center(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Checkbox(
                value: true,
                onChanged: (value) => print('hello world')),

              Text(
              '同意协议',
              textDirection: TextDirection.ltr,
              style: TextStyle(fontSize: 40),
              )
            ],
          ),
        ),
      ),
    )

  );
图片.png

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来对我们接下来学习一下如何利用StatelessWidget来对我们的代码进行重构;`

StatefulWidget我们放到后面的一个案例中来学习;

2.4.2: StatelessWidget

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

  • 它们的数据通常是直接写死(放在Widget中的数据)、必须被定义为final、为什么呢?我在下一个章节讲解StatefulWidget会讲到;
  • 从parent widget中传入的而且一旦传入就不可以修改。
  • 从InheritedWidget获取来使用的数据(这个放到后面会说明)
我们来看一下创建一个StatelessWidget的格式:
  • 1: 让自己创建的Widget继承自StatelessWidget;
  • 2: StatelessWidget包含一个必须重写的方法:build方法

class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    // <返回我么的Widget要渲染的Widget、比如一个Text Widget>
    return null;
  }
}
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即可
  • 另外、为了体现更好的封装性、我对代码进行了两层的拆分、让代码结构看起来更加清晰;(具体的拆分方式、我会在后面的案例中不断的体现出来、目前我们先拆分两层);
    重构代码如下:
main(List<String> args) {
  runApp(MyApp());
}


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("学习自定义StatelessWidget"),
        ),
        body: HomeContent(),
      ),
    );
  }
}

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Checkbox(
            value: true,
            onChanged: (value) => print('点击了Checkbox')),
          Text(
            '同意协议3',
            textDirection: TextDirection.ltr,
            style: TextStyle(fontSize: 50),
          )
        ],
      ),
    );
  }
}
图片.png

三:案例练习

3.1: 案例最终效果

我们先来看一下案例的最终展示效果;

  • 这个效果中我们会使用很多没有接触的Widget
  • 没有关系、后面这些常用的Widget我会一个个讲解
  • 这个案例最主要的目的还是让大家更加熟悉Flutter的开发模式以及自定义Widget的封装过程。


    图片.png

3.2: 自定义的Widget

main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      theme: ThemeData(
        primaryColor: Colors.brown
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("iPhone 11 介绍"),
        ),
        body: HomeContent3(),
      ),
    );
  }
}

class HomeContent3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
      child: ListView(
        children: <Widget>[
          ProductItem("iphone 11 pro", "更具美感的沉浸式界面。我们利用摄像头宽广的视角,让你可以看到取景框外的画面,而且轻点一下也能将它拍下来。这让你可以无阻隔地融于场景之中,更加专注地拍摄。", "https://www.apple.com/cn/iphone-11-pro/images/overview/camera/camera_redesigned_ui__sn27i66q2f62_large_2x.jpg"),
          ProductItem("iphone 11", "全新双摄系统取景范围更大,可将你的所见所爱尽收画面之中。iPhone 迄今最快的芯片和从早用到晚的电池续航,让你能做的事更多,却无需频频充电。而有了 iPhone 最高的视频画质,你所记录的那些美好时分,也会更加鲜活。", "https://www.apple.com/v/iphone-11/a/images/overview/design-gallery/design_gallery_2_purple__eztcnbruuiy6_large_2x.jpg"),
          ProductItem("Mac book Air", "这款 Mac 中的万人迷,注定再一次让人倾心。新款 MacBook Air 更薄、更轻,拥有金色、银色和深空灰色三种外观,配备加入了原彩显示技术的绚丽视网膜显示屏、触控 ID、新一代键盘,以及力度触控板。它标志性的楔形机身由 100% 再生铝金属打造,堪称 Mac 中的环保典范1。此外,它的电池续航能满足一天所需,是一个可以随身而行、事事胜任的好帮手。", "https://www.apple.com/v/mac/home/ai/images/overview/hero/macbook_air__csdfieli984m_large_2x.jpg")
        ],
      ),
    );
  }
}

class ProductItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;
  
  ProductItem(this.title, this.desc, this.imageURL);
  
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      padding: EdgeInsets.fromLTRB(20, 0, 20, 20),
      decoration: BoxDecoration(
        border: Border.all(),
      ),
      child: Column(
        children: <Widget>[
          SizedBox(height: 30,),
          Text(title, style: TextStyle(fontSize: 18)),
          SizedBox(height: 10,),
          Text(desc, style: TextStyle(fontSize: 15)),
          SizedBox(height: 5,),
          Image.network(imageURL)
        ],
      ),
    );
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容