类
在 Dart 中所有对象都是某个类的实例,所有类继承了 Object
类。
构造函数
import 'dart:math';
// 定义类
class Point {
num x = 0, y = 0;
// Point(this.x, this.y); // 构造器
// 或者
Point(x, y) {
this.x = x;
this.y = y;
print('这是构造函数,在实例化时触发');
}
// 实例方法
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}
main() {
// 调用类的构造函数,new 可以省略
Point p1 = new Point(1, 2); // 这是构造函数,在实例化时触发
Point p2 = Point(3, 4); // 这是构造函数,在实例化时触发
// 调用类方法
print(p1.distanceTo(p2)); // 2.8284271247461903
}
由于 Dart 2.12 的特性,这样写构造函数会报错:
class Point {
num x, y;
Point(x, y) { // 不可为空的实例字段 'x' 必须被初始化
// 尝试添加一个初始化表达式,或者在这个构造函数中添加一个字段初始化器,或者标记它
this.x = x;
this.y = y;
}
}
由于空安全,Dart 不知道你是否为 x,y 分配了变量。该写法在之前的版本没有问题,解决方法是dart - Non-nullable instance field must be initialized - Stack Overflow。
解决方法之一:
class Point {
num? x, y;
Point(x, y) {
this.x = x;
this.y = y;
}
}
num?
表示可空类型,表示变量值可以为空。
使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数使代码语义化,之前使用的 DateTime.now() 也是命名构造函数。
使用重定向构造函数,用冒号调用其他构造函数。
class Point {
num? x;
num? y;
Point.initX(y) { // 命名构造函数
this.x = 2;
this.y = y;
}
Point.redirctor(num x) : this(x, 0); // 重定向构造函数
}
main() {
Point p1 = Point.initX(2);
print('${p1.x}, ${p1.y}'); // 2, 2
Point p2 = Point.redirctor(1);
print('${p2.x}, ${p2.y}'); // 1, 0
}
代码越来越多导致维护性越来越差,所以我们需要把类抽离成文件,在需要的地方使用import
导入库。
// lib\Point.dart
class Point {
num x = 0, y = 0;
Point(this.x, this.y);
}
// main.dart
import 'lib/Point.dart';
main(){
//...
}
类及成员可见性
Dart 中的可见性以 library 为单位,每个Dart 文件就是一个库。
使用_
表示属性或方法的私有属性,相当于 Java 中的privite
。
class Point {
num _x = 0, _y = 0;
Point(this.x, this.y);
}
当其被抽离成一个文件时,私有属性的作用才生效。
getter,setter
每个变量都有其默认的getter
和setter
方法,final 声明的变量只可读,只有 getter
方法。
在 Dart 中,方法不能重载。
class Rect {
late num width, height;
Rect(this.width, this.height);
area() {
return this.width * this.height;
}
// getter
get area1 {
return this.width * this.height;
}
// setter
set height2(value) {
this.height = value;
}
}
main() {
Rect r1 = Rect(1, 2);
print(r1.area()); // 2
print(r1.area1); // 2
r1.height2 = 3;
print(r1.area1); // 3
}
初始化列表
初始化列表是在实例化之前进行的操作:
class Rect {
late num width, height;
// Rect(this.width, this.height); 不能同时使用
Rect()
: width = 2,
height = 3 {
print('in class');
print(this.width * this.height);
}
}
main() {
Rect r1 = Rect();
print('in main');
}
// 输出结果
// in class
// in main
// 6
static 静态成员
静态变量和静态方法可以通过类来访问,而不是类的实例。
class Person {
static String name = 'Jackie';
static void show() {
print(name);
}
}
main() {
print(Person.name); //Jackie
Person.show(); // Jackie
}
静态的方法不可以访问非静态的成员,非静态的方法可以访问静态的成员。
class Person {
static String name = 'Jackie';
static show() {
print(name);
}
showInfo() {
print(name);
show();
}
}
main() {
Person p = Person();
p.showInfo(); // Jackie Jackie
}
继承
-
子类使用
extends
关键词来继承父类; -
子类会继承父类里除构造函数的可见的属性和方法;
-
子类能复写父类的方法。
class Person {
late String name;
late int age;
Person(this.name, this.age);
work() {
print('$name is working.');
}
}
class Web extends Person {
late String sex;
// 子类的构造函数
Web(String name, int age, String sex) : super(name, age) {
this.sex = sex;
}
// 子类可以复写父类的方法
@override // 表示覆写父类的方法,选写
work() {
print('$name is working 996.');
}
}
main() {
Web w = Web('Tom', 20, 'male');
print(w.sex); // male
w.work(); // Tom is working 996.
}
抽象类
Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。
- 抽象类通过
abstract
关键字来定义。 - Dart 中没有方法体的方法称为抽象方法。
- 如果子类继承抽象类必须要实现里面的抽象方法。
- 如果把抽象类当做接口实现的话必须要实现抽象类里面定义的所有属性和方法。
- 抽象类不能被实例化,只有继承它的子类可以。
extends
抽象类和 implements
的区别:
- 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用
extends
继承抽象类。 - 如果只是把抽象类当做标准的话就用
implements
实现抽象类。
abstract class Person {
late String name;
late int age;
Person(this.name, this.age);
work(); // 抽象方法
}
class Employee extends Person {
Employee(String name, int age) : super(name, age);
@override
work() {
print('$name is working 996.');
}
}
class Employee2 extends Person {
Employee2(String name, int age) : super(name, age);
@override
work() {
print('$name is working 669.');
}
}
main() {
Person e = Employee('Tom', 20);
e.work(); // Tom is working 996.
// Person p = Person(); //报错,抽象类不能实例化
Person e2 = Employee2('Jerry', 20);
e2.work(); // Jerry is working 669.
}
多态
是子类的实例赋值给父类的引用,允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。
多态就是父类定义一个方法,让继承他的子类去实现,每个子类有不同的表现。
上述例子中,Employee 和 Employee2 类都实现了多态。
接口
Dart 也有接口,但是和 Java 有区别。
Dart 的接口没有 interface 关键字,而是普通类或抽象类都可以作为接口使用 implements
关键字被实现。
如果实现的类是普通类,会将普通类和抽象类中的属性的方法全部需要覆写一遍.而因为抽象类可以定义抽象方法,普通类不可以,所以建议使用抽象类定义接口。
abstract class Db {
late String uri;
add(String data);
}
class Mysql implements Db {
@override
late String uri;
Mysql(this.uri);
@override
add(String data) {
print('This is Mysql. ' + '$data');
}
}
main() {
Mysql m = Mysql('xxx');
m.add('123');
}
接口抽离成不同的文件:
// lib\Db.dart
abstract class Db {...}
// lib\Mysql.dart
import 'lib/Db.dart';
class Mysql implements Db {...}
// main.dart
import 'lib/Mysql.dart';
main() {...}
一个类可以实现多个接口
class C implements A, B {
// A, B 接口所有的属性和方法
}
Mixins
Class 中无法实现多继承,Mixins 不同于继承和接口,可以实现类似多继承的功能:
class C extends A, B {} // 报错
class C with A, B {...} // √
- 作为 Mixins 的类只能继承自Object,不能继承其他类。
- 作为 Mixins 的类不能有构造函数。
- 一个类可以 Mixins 多个 Mixins 类。
- Mixins 绝不是继承,也不是接口,而是一种全新的特性。
class A {...}
class B extends A {...}
class C {...}
class D with B, c {...} // 报错
class D extends A with B, C {...} // √
后写的类会覆盖掉前面的类:
class C with A, B {...} // B 的方法会覆盖掉 A
class D extends A with B, C {...} // B 的方法会覆盖掉 A,C 的方法会覆盖掉 A 和 B
最后
有小伙伴私信问Compose的问题,好不好用啊,现在要不要学啊?
其实答案很简单,自从谷歌2019年公布了声明式UI框架Jetpack Compose后,两年多的时间,各种大力宣传,和大量资源的倾斜,API功能都趋于稳定了。
至于好不好用,各种用过的同行都是持肯定态度的。优势大概就是这四点:
强大的工具和直观的Kotlin API
简化并加速了Android上的UI开发
可以帮助开发者用更少更直观的代码创建View
有更强大的功能,以及还能提高开发速度
这么大的优势,毋庸置疑,肯定是要学的嘛,而且越快掌握越好。别等刀架到脖子上了,才去练金钟罩。
至于怎么快速上手,可以给大家免费分享一份**《Jetpack Compose 完全开发手册》**,手把手教大家从入门到精通。
第一章 初识 Jetpack Compose
-
为什么我们需要一个新的UI 工具?
-
Jetpack Compose的着重点
加速开发
强大的UI工具
直观的Kotlin API
- API 设计
- Compose API 的原则
一切都是函数
顶层函数(Top-level function)
组合优于继承
信任单一来源
- 深入了解Compose
Core
Foundation
Material
- 插槽API
第二章 Jetpack Compose构建Android UI
- Android Jetpack Compose 最全上手指南
Jetpack Compose 环境准备和Hello World
布局
使用Material design 设计
Compose 布局实时预览
……
- 深入详解 Jetpack Compose | 优化 UI 构建
Compose 所解决的问题
Composable 函数剖析
声明式 UI
组合 vs 继承
封装
重组
……
- 深入详解 Jetpack Compose | 实现原理
@Composable 注解意味着什么?
执行模式
Positional Memoization (位置记忆化)
存储参数
重组
……
第三章 Jetpack Compose 项目实战演练(附Demo)
- Jetpack Compose应用1
开始前的准备
创建DEMO
遇到的问题
- Jetpack Compose应用2
- Jetpack Compose应用做一个倒计时器
数据结构
倒计时功能
状态模式
Compose 布局
绘制时钟
- 用Jetpack Compose写一个玩安卓App
准备工作
引入依赖
新建 Activity
创建 Compose
PlayTheme
画页面
底部导航栏
管理状态
添加页面
- 用Compose Android 写一个天气应用
开篇
画页面
画背景
画内容
……
- 用Compose快速打造一个“电影App”
成品
实现方案
实战
不足
……
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
有需要的话可以点下面二维码免费领取↓↓↓