接触Flutter有几天了,总觉得该写点什么,在写的过程中,发现自己更懂了一点Flutter。
用Android studio新建一个Flutter项目,有三处会出现Material:
(1)main.dart第一行,import 'package:flutter/material.dart';
(2)main.dart第11行return MaterialApp
(3)pubspec.yaml第45行uses-material-design: true
有几个疑问:
1.material是什么?material.dart是什么?material-design是什么?
从https://flutterchina.club/网站上有一句原话如下:
使用Flutter内置美丽的Material Design和Cupertino(iOS风格)widget、丰富的motion API、平滑而自然的滑动效果和平台感知,为您的用户带来全新体验。
可以看出,所有Material相关的可能都是一个东西,那就是一套叫Material的开发组件。再说直白一点,就是一个官方已经写好的一个类库,material.dart里面包含的就是所有对外开放类库的头文件。这个时候应该打开默认创建的Flutter项目,按住command键+鼠标左键,看下material.dart的具体内容。
那么uses-material-design: true这句话就很好理解了?试想:如果要使用Material的开发组件,则在pubspec.yaml中告诉编辑器即可。只有告诉编辑器之后,我们使用import 'package:flutter/material.dart';导入头文件才没有问题。
事实是这样吗?将pubspec.yaml第45行uses-material-design: true中的true改为false,或者将整行前面加个#注释掉。发现了两个问题:(1)导入头文件并不会发生错误,程序运行一切正常(2)运行出来的程序确实有一点不一样,加号按钮变成了一个锁🔐。
这时候肯定会想,为什么没发生错误?按照iOS或者安卓导入第三方库的经验,没有加载库,怎么可能导入头文件成功。再仔细多看一眼,查看material.dart的路径,发现material.dart本来就是Flutter包里面的内容。我们的AS里面本来就有Flutter包,路径也配置好了,pubspec.yaml第23行已经加了Flutter库的依赖,相当于Flutter库已经导入到项目,运行当然不会报错了。这个时候再看一眼Flutter包里面到底有哪些东西。
查看一下src,发现里面全是这些头文件的具体实现。原来如此,Flutter就是这么个玩意。总算懂了第一个问题,那么第二个问题为啥?再看到pubspec.yaml第45行uses-material-design: true的注解部分,第42行到第44行,注解如下:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true的作用仅仅是决定Material图标是否应用到项目中。
到这里,大概明白了material的外表是什么东西。在到官网上和代码中找一找,看能否发现更多端倪。material.dart和widgets.dart是两个头文件,为啥我们在使用的时候没有导入widgets.dart?再看一眼material.dart里面的内容,在最下面,有一个export 'widgets.dart';原来我们再导入material.dart之后,已经有widgets.dart了。那么Flutter包中文件之间的关系,我们就明白了。并不是导入了material之后,所有的类库都会帮我们加载。在到官网上看看https://flutterchina.club/widgets/,发现Cupertino(iOS风格的widget)是另外一个设计风格。同样,cupertino.dart的底部也包含了widgets.dart。而animation.dart,foundation.dart等其他的文件并没有包含widgets.dart,那么他们之间关系,我们又清楚了更多。那开发的时候,使用的功能属于什么类,我们是否应该导入,为什么要导入,就很清楚了。
两个风格material和cupertino,对比之下,一目了然。
到目前还是没有搞清楚return MaterialApp ,这个帮我们做了什么,从哪来,要到哪去?command+鼠标左键点击进去看看,发现它是位于Flutter => lib => src => material => app.dart这个路径下面。看一眼src =>material里面的所有文件,再随便浏览一下app.dart里面的几行代码,大概能确定,跟APP风格,主题相关的这种全局配置定义,而且是final修饰的一大堆变量,可能APP全局配置就在这个文件里面做了。
但是在将文件最上面的头文件打开的时候,发现app.dart里面居然有一句import 'package:flutter/cupertino.dart';app.dart居然导入了'package:flutter/cupertino.dart'。
所以,你别以为Material和cupertino是完全独立,完全不同风格的两套组件。到cupertino的app.dart中去看,并不会发现Material。那就有结果了,Material其实是包含cupertino的,cupertino只是对Material中某些控件的第二种封装,部分组件提供额外一套风格的选择。那么可以猜测一下,我们以后99%的Flutter开发项目都会基于Material。
继续往下看,回到Material =》app.dart,第165行const MaterialApp({,把鼠标上下滑几下,MaterialApp具体内容暂时不管,看到this.home,this.theme猜一下,大概就是整个类里面的所有参数都可以通过MaterialApp这个方法设置。再看对这个方法的注解:
/// Creates a MaterialApp.////// At least one of [home], [routes], [onGenerateRoute], or [builder] must be/// non-null. If only [routes] is given, it must include an entry for the/// [Navigator.defaultRouteName] (`/`), since that is the route used when the/// application is launched with an intent that specifies an otherwise/// unsupported route.////// This class creates an instance of [WidgetsApp].////// The boolean arguments, [routes], and [navigatorObservers], must not be null.
很明确了,这个方法是用来创建一个Material组件的APP,那么可以这么说,任何使用Material的APP,都会使用这个方法,那么自然而然想到一个问题,每个Material组件的APP是否只会调用一次MaterialApp?如果是,那么以后根本不用管main函数在哪,我们直接从MaterialApp开始不就可以了么。但会不会像iOS中scene或者根视图那样,可以跑多个?我觉得应该对app.dart文件搜索MaterialApp,到底怎么说的?然而并没有直接的说明这个问题,没有任何一个地方说明可以在APP中调用两次MaterialApp,都是用a,一个。但也只能80%肯定,就此作罢,在往下看,能否找到答案。
第二句,至少[home], [routes], [onGenerateRoute], or [builder]中有一个不为空。不是4个都不为空,我特意看了一下,在默认创建的工程中,MaterialApp只有3个参数:title,theme和home。我有点想试试,是不是真的,把title,theme注释掉,程序照常运行;但把home注释掉,果然出错了
那么意思就是MaterialApp里面会包含一个根route,这个玩意就是RootViewController,整个APP不可能跳出这个根。所以回头再想,MaterialApp肯定就只会调用一次了。所以建立Material项目的第一步就是构建MaterialApp。
再往上看看,第50行到第58行
/// An application that uses material design.////// A convenience widget that wraps a number of widgets that are commonly/// required for material design applications. It builds upon a [WidgetsApp] by/// adding material-design specific functionality, such as [AnimatedTheme] and/// [GridPaper].////// The [MaterialApp] configures the top-level [Navigator] to search for routes/// in the following order:///
可以看出还有一种构建APP的方式WidgetsApp。而MaterialApp是在WidgetsApp的基础上,添加了material-design组件库的功能。
在app.dart中注释代码中,发现另外一个问题,每次MaterialApp都会用到Scaffold,那么Scaffold到底是什么玩意?
* [Scaffold], which provides standard app elements like an [AppBar] and a [Drawer].
我觉得应该再研究一下Scaffold,Scaffold到底是什么?做了什么,从哪来,到哪去?
初学水平有限,可能有误,欢迎交流