声明:以下内容绝大部分参考以下这本书,谢谢作者分享
1、当然,如果你是iOS开发者,也不用担心,Dart中也有一些与Swift比较相似的特性,如命名参数等,笔者当时学习Dart时,只是花了一个小时,看完Dart官网的Language Tour,就开始动手写Flutter了。
2、新东方、咸鱼、字节跳动都用了flutter
3、选择那个…控件后,试了几次成功了,download 失败,直接输入也失败
4、工程拿出来有bug
5、Object 是Dart所有对象的根基类,也就是说所有类型都是Object的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object声明的对象. dynamic与var一样都是关键词,声明的变量可以赋值任意对象。 而dynamic与Object相同之处在于,他们声明的变量可以在后期改变赋值类型。
6、dynamic与Object不同的是,dynamic声明的对象编译器会提供所有可能的组合, 而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错。
7、dynamic的这个特性与Objective-C中的id作用很像. dynamic的这个特点使得我们在使用它时需要格外注意,这很容易引入一个运行时错误.
8、Dart是一种真正的面向对象的语言
9、所以即使是函数也是对象,并且有一个类型Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征。
10、Dart函数声明如果没有显式声明返回值类型时会默认当做dynamic处理
11、bool isNoble (int atomicNumber)=> _nobleGases [atomicNumber] != null
对于一个包含一个表达式的函数,可以使用简写语法
12、包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面:
String say(String from, String msg, [String device]){
var result = ‘$from says KaTeX parse error: Expected '}', got 'EOF' at end of input: … result = ‘result with a $device’;
}
return result;
}
13、定义函数时,使用{param1, param2,….},放在参数列表的最后面,用于指定命名参数,例如:
1.4.3
Dart 类库有非常多的返回Future或者Stream对象的函数。这些函数被称为异步函数:它们只会设置好一些耗时操作之后返回,比如像IO操作。而不是等到这个操作完成。
async 和await关键词支持了异步编程,允许您写出和同步代码很像的异步代码
1.4.4 Stream 也是用于接收异步事件的数据,和Future不同的是,它可以接收多个异步操作的结果(成功或失败)。也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。
1.4.5
但笔者相信,随着Flutter的逐渐火热,会回过头来反推Dart生态加速发展,对于Dart来说,现在需要的是时间。
1.4.6
所以单从这一点来看,Dart并不具备什么明显优势,但综合起来看,Dart既能进行服务端脚本、APP开发、web开发,这就有优势了!
1.4.7
笔者还是很看好Dart语言的将来,之所以表这个态,是因为在新技术发展初期,很多人可能还有所摇摆,有所犹豫,所以有必要给大家打一剂强心针,当然,这是一个见仁见智的问题,大家可以各抒己见。
1.4.8
flutter build apk 这个命令要在根部执行
1.4.9 flutter build ios —release 不行
添加这个就行了
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
很奇怪,不是昨天就在的吗
1.5.0
dart framework:
Material , Cupertino, Widgets, Rendering, Animation, Painting, Gestures, Foudation
其中:Material 是一种标准的的移动端和web端的视觉设计语言,Flutter默认提供了一套丰富的Material风格的组件
1.5.1
Everything’s a Widget
每件事都是一个小部件
1.6 widget 学习

-
Flutter快速上车之Widget
-
1.6.1
Flutter的设计思想就是完全的widget化
-
1.6.2
Flutter的设计思想就是完全的widget化
-
1.6.3
Decoration 是对container 进行装饰的描述
-
1.6.4
flutter 官方也意识到了这个问题,他们从实际编写效率的角提供了一个友好高效的封装,这就是Container
-
16.5
Decoration是对Container进行装饰的描述。其概念类似与android中的shape。一般实际场景中会使用他的子类BoxDecoration。BoxDecoration提供了对背景色,边框,圆角,阴影和渐变等功能的定制能力。
-
16.6
路由管理
- 1.7.1
路由在移动开发中通常指页面(page) ,这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController,所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。Flutter 中的路由管理和原生开发类似,无论是android 还是iOS,导航管理都会维护一个路由栈,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作,二路由管理主要是指如何来管理路由栈。
- 1.7.2
MaterialPageRoute
MaterialPageRoute 继承自PageRoute 类,PageRoute类是一个抽象类,表示占有整个屏幕空间的一个模态路由页面,它还定义了路由构建及切换时过度动画的相关接口及属性。
继承关系extends
- 使用关键字extends继承一个类
- 子类会继承父类可见的属性和方法,不会继承构造方法
- 子类能够复写父类的方法,getter和setter
- 单继承,多态性
pub 仓库
- 上文所述的依赖方式是依赖Pub仓库的。但我们还可以依赖本地包和git仓库。
- 依赖git ,你也可以依赖存储在git仓库中的包。例如
dependencies:
pkg1:
git:
url: git://github.com/xxx/pkg1.git
- 上面的嘉定包位于git存储库的根目录中,如果不是这种情况,可以使用path参数指定相对位置,例如:
dependencies:
package1:
git:
url: git://github.com/flutter/packages.git
path: packages/package1
资源管理
- 常见类型的assets包括静态数据(例如json文件)、配置文件、图标和图片(JPEG,webp,gif,动画webp/gif,png,bmp,和wemp)等
- assets 指定应包含在应用程序中的文件,每个asset都通过相对于pubspec.yaml文件所在的文件系统路径来标识自身的路径。
- asset的声明顺序书无关紧要的,asset 的实际目录可以是任务文件夹
- 那么两个graphics/background.png和graphics/dark/background.png都包含在您的asset bundle 中,前者被认为是 main asset(主资源),后者被认为是一种变体(variant)
调试工具
- 在运行应用程序前,请运行flutter analyze 测试你的代码。这个工具是一个静态的检查工具。
- 一个中间模式可以关闭除Observatory 之外所有调试辅助工具的,称为’profile mode’,用–profile 替代 --release即可。
- 这里面有很多工具,细细品读
异常捕获和线程模型
- 在java和oc中,如果程序发生异常且没有被捕获,那么程序会终止,但是这在dart或者javascript中则不会。
- java和oc都是多线程模型的编程语言,任意一个线程触发异常且该异常未被捕获时,就会导致整个进程退出。但是dart和javascript不会,它们是单线程模型,运行机制很相似。
- Dart在单线程中是以消息循环机制来运行的,其中包含两个任务队列,一个是“微任务队列”microtask queue,另一个叫做"事件队列"event queue.微任务队列的执行优先级别高于事件队列。
- 如果微任务太多,执行时间总和就越久,事件队列任务的延迟也就越久,对于GUI应用来说最直观的表现就是比较卡,所以必须得保证微任务队列不会太长。
- 在事件循环中,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其它任务执行的。
- Dart中可以通过try/catch/finally来捕获代码块异常
Widget 简介
- 与原生开发中的"控件"不同的是,Flutter中的Widget的概念更广,它不仅可以表示UI元素,也可以表示一些功能性的组件如: 用于手势检测的GestureDectector Widget ,用于App主题数据传递的Theme等等
- 在flutter 中,Widget的功能是继承DiagnosticableTree,是诊断树。
Widget状态管理
- 在widget内部管理状态封装性会好一些,而父Widget中管理会比较灵活,有些时候,如果不确定到底怎么管理状态,那么推荐的首选是在父widget中管理(灵活会显得更重要一些)
- StatelessElement 用于不需要维护状态的场景,它通常在build方法中通过嵌套其它Widget来构建UI,在构建过程中递归的构建其嵌套的Widget。
- class _MyHomePageState extends State
这么写的目的是什么,告诉这个方法是交给谁来用的,去掉也能跑。
setState() {
_counter++;
};
setState(() {
_counter++;
});
这两种写法只有第二种方法才是正确的,第一种方法不行的。
TextSpan
- 在上面的例子中,Text的所有文本内容只能按同一样式,如果我们需要对一个Text的内容的不同部分按照不同的样式显示,这时就可以使用TextSpan,它代表文本的一个"片段"
DefaultTextStyle
- 文本的样式默认是可以被继承的(子类文本类组件未指定具体样式时可以使用Widget树中父级设置的默认样式)
输入框和表单
- controller 编辑框的控制器,通过它可以设置/获取编辑框的内容,选择编辑内容,监听编辑文本改变事件。大多数情况下我们都提供一个controller来与文本框交互。如果没有 提供controller,则TextField内部会自动创建一个。
- FLutter 提供了一个form组件,它可以对输入框进行分组,然后进行一些统一操作,如输入内容检验、输入框重置以及输入内容保存。
- From继承自Statefulwidget对象,它对应的状态类为FormState.
container
- 可以发现,直观的感觉就是margin的留白是在容器外部,而padding的留白是在容器内部,读者需要记住这个差异。
Center
- Creates a widget that centers its child
让这个widget在它的孩子中间,换句话说,孩子也在这个widget中间。
- 其实大多数时候,我们是不需要关心key对,但是如果我们需要对处于某种状态的相同类型的控件集合进行添加,删除或重新排序时,我们就需要用到key了
Flex
源码简单的令人发指,只有三个传值,这里我们只关注两个:
- flex
- child
展开[row],[Column]或[Flex]的子代的小部件
层叠布局
- Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位
- 层叠布局和Web中的绝对定位、Android中的Frame布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。
Stack
- fit:此参数用于确定没有定位的子组件如何去适应Stack的大小。StackFit.loose表示使用子组件的大小,StackFit.expand表示扩伸到Stack的大小。
- overflow:此属性决定如何显示超出Stack显示空间的子组件;值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。
- InheritedWidget是Flutter中非常重要的一个功能型组件
构造函数
- 如果未声明构造函数,则会提供默认构造函数。 默认构造函数没有参数,并在调用父类无参数构造函数。
- 子类不能继承其父类构造函数,一个没有声明构造函数的子类只有默认(无参数,无名称)构造函数
- 如果父类没有未命名的无参数构造函数,则必须手动调用父类中的一个构造函数。 在子类的构造函数体之后用冒号(:)指定父类构造函数
代码执行顺序
- 初始化列表
- 父类的无参数构造函数
- 子类的无参数构造函数
跨组件共享
- 如果状态要跨组件共享,则该状态应该由各个组件共同的父元素来管理
通知
- class NotificationListener extends StatelessWidget
NotificationListener 可以指定一个模板参数,该模板参数类型必须是继承自Notification
context
- 我们说过context实际上就是操作Element的一个接口,它与Element树上的节点是对应的,通知会从context对应的Element节点向上冒泡。
动画
- addListener();它可以用于给Animation添加帧监听器,在每一帧都会被调用。帧监听器中最常见的行为是改变状态后调用setState()来触发UI重建。
animation = new Tween(begin: 0.0, end:300.0).animate(controller);
animation. addListener((){
setState(() {
});
});
等价于
animation = new Tween(begin: 0.0, end:300.0).animate(controller)
.. addListener((){//注意这里加了两个点号,以及上一行的分号去掉
setState(() {
});
});
多继承
- class Cow extends Animal with Donwu{//with表示实现多继承,实例化cow的时候,可以用cow对象,调用Animal
注意书写规范
- 错误的写法即使在没执行的代码里面,只要没有注释掉,就会报错
构造函数
- 如果父类没有无名无参数的默认构造函数,则子类必须手动调用一个父类构造函数。在:后面构造函数体之前指定要调用的父类构造函数
- 调用父类构造函数
默认情况下,子类中的构造函数调用父类的未命名无参数构造函数。 父类的构造函数在子类构造函数体的开头被调用。 如果还使用初始化了列表,则会在调用父类构造函数之前执行。 执行顺序如下:
初始化列表
父类的无参数构造函数
子类的无参数构造函数
如果父类没有未命名的无参数构造函数,则必须手动调用父类中的一个构造函数。 在子类的构造函数体之后用冒号(:)指定父类构造函数
动画过渡组件
- 为了表述方便,本书约定,将在Widget属性发生变化时会执行过渡动画的组件统称为”动画过渡组件“
- 因此,如果也能将AnimationController进行封装,则会大大提高动画组件的易用性。
泛型
- 泛型如果为null可以省略不写,为了便于维护和管理,开发中建议加上泛型
- //使用泛型,则可以省去为每一种类型单独编写代码
abstract class Cache {
T getByKey(String key);
void setByKey(String key, T value);
}
表示类里面需要用到数据T,它是一个泛型。代表一个抽象的数据。
- 限制泛型类型
class Foo {
// Implementation goes here…
String toString() => “Instance of ‘Foo<$T>’”;
}
class Extender extends SomeBaseClass {…}
//使用时可以传入 SomeBaseClass 或者其子类
var someBaseClassFoo = Foo();
var extenderFoo = Foo();
//也可以不传入参数,默认为 SomeBaseClass
var foo = Foo();
print(foo); // Instance of ‘Foo’
//传入其他类型的参数则会报错
var foo = Foo();//error
- 泛型方法
T first(List ts) {
// Do some initial work or error checking, then…
T tmp = ts[0];
// Do some additional checking or processing…
return tmp;
}
函数的返回值类型 (T).
参数的类型 (List).
局部变量的类型 (T tmp).