dart笔记
main()
print('你好 dart');
}
//必须要写分号
main 方法为dart的主入口
//void 表示没有返回值
void mian (){
print('some');
}
变量定义
1.如果直接写的var 会进行类型推导
- 创建且没有赋值 那么值默认为null
- 如果有值 那么会进行类型推断一旦进行类型推断后,那么不能再进行类型修改
var name = '1111'
print(name)
2.直接规定类型
//String 字符串类型
//int 数字类型
void main(){
String name = '111';
int age = 22;
print(age);
print(name);
}
3.变量名跟其他的语言一致
4.允许一个未初始化的变量拥有一个默认值null,在类型后面加?
int? lineCount;
assert(lineCount == null);
var 关键字和 数据类型关键字不能同时使用
常量定义
const 创建常量时要赋值
//const 值不能改变 创建常量时要赋值
//创建时就冻结数据
void main(){
const name = '111';
print(name);
}
final 创建时可以不赋值,单后续也不能修改
//可以修改一次(初始化的时候不会讲数据固定成变量 而是执行时,不是说可以进行赋值修改)
//如果是const 的话 会报错
main (){
final name = new DateTime.now();
print(name);
}
数据类型
1.字符串类型
字符串定义的几种方式
-
通过var 类型推断
main (){ var str = '111' print(str); } -
string 关键字
main (){ string str = '111' print(str); } -
三个单引号或者双引号(''')写多行文字 普通的单个字符串只能写一行
main (){
var str = ''' 111 111
111111
111111
''';
print(str);
}
2.字符串
-
在引号中 使用$符合 对应变量 有点像字符串模板,如果表达式的结果为一个对象,则 Dart 会调用该对象的
toString方法来获取一个字符串。通过 + 号拼接
main(){
String str1 = '你好';
String str2 = 'dart';
print('$str1$str2');
print(str1+str2);
}
-
使用三个单引号或者三个双引号也能创建多行字符串:
var s1 = ''' 你可以像这样创建多行字符串。 '''; var s2 = """这也是一个多行字符串。"""; -
在字符串前加上
r作为前缀创建 “raw” 字符串(即不会被做任何处理(比如转义)的字符串var s = r'In a raw string, not even \n gets special treatment.'; // 代码中文解释 var s = r'在 raw 字符串中,转义字符串 \n 会直接输出 “\n” 而不是转义为换行。';
3.数值类型
-
int 整数类型 无小数位 如果带有小数位 则会报错
-
如果在创建变量时没有赋值 则不能直接使用
void main(){ int a = 11; print(a); //11 } -
double 浮点型 带有小数位
//也可以是int型 如果不写小数位,会增加小数位0,写了就带小数位一起输出 void main(){ double a = 111; print(a); //111.0 } -
运算符 + - * % / 如果有小数位 最终结果会被转为浮点型
void main(){ double a = 111; int b = 2; print(a/b); //55.5} -
数值类型和其他类型的转换
// String -> int var one = int.parse('1'); assert(one == 1); // String -> double var onePointOne = double.parse('1.1'); assert(onePointOne == 1.1); // int -> String String oneAsString = 1.toString(); assert(oneAsString == '1'); // double -> String String piAsString = 3.14159.toStringAsFixed(2); assert(piAsString == '3.14');
4.布尔类型
-
bool值 true/false
void main(){ bool flag = true; print('good'); } -
//条件判断语句
////类型不一致 不能直接进行大于 小于的比较//类型不一致 可以进行 等于的比较void main(){ bool flag = true; if(flag){ print('good'); } int a = 123; int b = '345'; if(a>b){ print('a>b'); }else{ print('a < b'); }}
5.List类型(数组/集合)
1.第一中定义List方式 直接通过赋值
void main(){ var l1 = [11,'111',true]; print(l1); print(l1.length); //获取数组长度 print(l1[0]); //通过下标获取数据}
2.第二种定义List方式 规范数据集类型
void main(){ var l1 = <String>[ '111']; print(l1);}
3.第三种定义List方式 => 赋值方括号 []
增加数据 通过[]创建的集合 是可以变化的
void main(){ var l1 = []; l1.add('张三'); l1.add('李四'); print(l1);}
4.第四种定义List的方式 => List.filled
// var l6 = new List(); //在新版本的dart里面已经无法使用了 但是flutter 支持main (){ //官方提供的api //创建一个固定长度的集合 参数一 为长度 参数二 为填充内容 var l6 = List.filled(2,''); print(l6); print(l6[0]); //通过下标修改数据 l6[0] = '张三'; l6[1] = '李四'; print(l6); //此时会报错 l6.add('王五'); //此时也会报错 不能修改长度 通过[] 创建的List 可以改变长度 l1.length = 0; l6.length = 2; }
main(){
//filled形式规范类型
//如果不写类型的话 会有类型推导 填充值即为类型规范
//如果填充为int型,那么修改的话 直接填入int型
var l7 = List<String>.filled(2,'111')
}
5.第五种通过 类似var 只不过规范类型
main(){
List list = ['aaa'];
print(list);
List list1 = [
{
"title":'name'
}
];
print(list[0]['title'])
}
6.Dart 在 2.3 引入了 扩展操作符(...)和 空感知扩展操作符(...?)
//使用扩展操作符(...)将一个 List 中的所有元素插入到另一个 List 中
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
//如果扩展操作符右边可能为 null ,你可以使用 null-aware 扩展操作符(...?)来避免产生异常//根据判断来是否要展开var list;var list2 = [0, ...?list];assert(list2.length == 1);
7.数组中加入if和for操作,在构建时可以使用if语句和for循环
//使用if 判断是否要加入该数据main() { bool? promoActive = true; var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet']; print(nav);}
//使用for 循环遍历数据插入main(List<String> args) { var listOfInts = [1, 2, 3]; var listOfStrings = ['#0', for (var i in listOfInts) '#$i']; print(listOfStrings[1] == '#1');}
6.Maps(字典)
有点类似js的json,key是唯一的
第一种定义Maps的形式 => 直接var 一个花括号对象
main(){
var person = {
"name":'张三',
"age":20,
"work":['程序猿','送外卖']
};
print(person['name']);
}
第二种定义Maps方法 => new Map()
生成空的map,需要动态增加
main(){
var p = new Map<String,String>();
p['name'] = '李四';
p['age'] = 20; //报错
p['word'] = ['程序猿'];
print(p);
}
规范map的类型 (key和value进行类型规范)
main(){
Map<String,String> _map = Map();
_map['name'] ='张三';
print(_map);
}
通过Map 类型创建 类似与var
main(){ Map map = { "name":"沾三" }; print(map)}
定义常量Map
final constantMap = const { 2: 'helium', 10: 'neon', 18: 'argon',};
7.sets
与js的set类似,其功能与数组类似,是表示无序集合,但是特点的是不会有重复数据
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
类型限制
//{} 默认是map类型,如果加上<String> 则表示set类型var names = <String>{}
插入数据
var elements = <String>{};var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};elements.add('fluorine');elements.addAll(halogens);//set长度assert(elements.length == 5);
定义常量Set
final constantSet = const { 'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine',};constantSet.add('aaa');// Cannot change an unmodifiable set 会报错
从 Dart 2.3 开始,Set 可以像 List 一样支持使用扩展操作符(... 和 ...?)以及 Collection if 和 for 操作
数据定义总结
- 通过var 的形式定义变量,类似js,右边的值可以自定定义,且类型自动推断,可以扩展数据,初始化可以不赋值,dart会设置默认值为null(包括List和Mps)
- 通过类型关键符创建,初始化必须要赋值,
- 定义常量只有final和const,类似var的用法
- 最关键的是 const/var 不能和类型关键字同时使用
判断数据类型
通过is关键字 判断类型 如果是 则会返回true
main(){
var str = '1234';
if(str is String){
print('string类型');
}else if(str is int){
print('int类型');
}else if(str is double){
print('double类型');
}else{
print('其他类型');
}
}
运算符
算术运算符
// 算术运算符
// + - * / % ~/
//加 减 乘 除 取余 取整
//如果运算结果有小数位 那么数据会变为浮点型
main(){
int a = 15;
int b = 8 ;
print(a - b); //7
print(a + b); //23
print(a * b); //120
print(a / b); //1.875
c = a/b;
var d = c is double //true
print(a % b); //7
print(a ~/ b); // 1 舍去小数位
}
关系运算符
//== != > < >= <=
//等于 不等于 大于 小于 大于等于 小于等于
//返回值只有true false
main(){
int a = 11;
int b = 22;
if(a == b){
print('a == b');
}else if(a>b){
print('a > b');
}
}
逻辑运算符
// 逻辑运算符
//! 逻辑取反
//&& 并且 全部为true时 返回true 有一个false 返回false
//|| 或者 有一个为true返回true 全部为flase返回false
//不能使用 ture || print('xx') 这样 只能进行逻辑比较
main(){
bool flag = true;
print(!flag); //false
bool a = true;
bool b = false;
print(a && b); //false
print(a || b) //true
}
main (){ int age = 20; String sex = '女'; if(age == 20 && sex == '女'){ print('$age---$sex'); }}
赋值运算
//1.基础赋值运算符 == ??=
//?= 如果左边的的值为空的话 则会进行赋值操作 如果不为空 则不会赋值
main(){
int a = 2;
int b = 3;
int c = a + b ; //从右先左
var d;
d ??= 11;
print(d); //1
var e = 0;
e ??= 1;
print(e); //0
}
符合赋值运算符
//+= -= %= /= ~/= *=
main(){
var a = 1;
a += 10; //表示 a = a + 10
print(a);
}
条件表达式
if else
main(){ bool flag = true; if(flag){ print('true'); }else{ print('false'); }}
main(){ //判断一个人的成绩 >=60 显示及格 >=70 表示良好 >=90 表示优秀 const score = 80; if(score>10){ print('异常'); }else if(score>=90){ print('优秀'); }else if(score>=70){ print('良好'); }else if(score>=60){ print('及格'); }else{ print('不及格'); }}
switch case
main (){ const sex = '男'; switch(sex){ case "男": print('性别是$sex'); break; case '女': print('性别是$sex'); break; default: print('性别错误'); } }}
三目运算符
main(){ var flag= true; String c = flag ? 'ok' : 'false';}
?? 运算符
main(){ var a; //如果a 为null时 将10赋值给b 有点类似于js 的|| int b = a ?? 10; print(b) ; }
数据类型转换
1.Number 与String 类型之间的转换
- Number 类型转换成String类型 toString()
- String类型转为Number类型 parse() => int.parse
- 整数只能使用int.parse 如果是小数使用,会报错
- 浮点型 可以使用double.parse double 兼容两种类型
//字符串转数字 main(){ String str = '123'; var myNum = double.parse(str); print( myNum is double); }
//数字转字符串main(){ var str = 111; var myStr = str.toString(); print( myStr is String);}
Try catch
如果是 空字符串('') 转换成数字类型的时候 会报异常
//处理类型转换异常 使用try catch main(){ String str = ''; try{ var myNum = double.parse(str); print(myNum); }catch{ print(0); } }
2,其他类型转为Boolean 类型
isEmpty :判断字符串是否为空
main(){
var str = '';
if(str.isEmpty){
print('为空'); //为空
}else{
print('非空');
}
}
isNaN 判断是不是NaN 不是数字
main(){
var a = 0 / 0;
print(a.isNaN); //true
}
自增自减运算
//++ -- 相当于+=1 -=1
//++/-- 写在前面表示赋值前先运算 写在后面表示先赋值 后运算
main(){
var a = 1;
var b = a++;
print(b) ; // 1
var c = ++b;
print(c) ; //2
}
循环
for循环
//跟js一样
main(){
List list = ['1','2'];
for(int i = 0;i<list.length;i++){
print(list[i]);
}
}
while /do ...while
//和js一样main(){ var count = 10; while(count>0){ print(count); count--; }}//do while main(){ var count = 10; do{ print(count); count--; }while(count>0); }
Continue和break 与js一样
//continue 跳过当前循环
//break 中断循环 只能跳出一层
List的属性和方法
list的属性
main(){ List list = ['苹果','香蕉']; print(list.length); //获取list 长度 print(list.isEmpty); //判断list 是否为空 print(list.isNotEmpty); //不是空 print(list.reversed); //翻转list 返回的是(xx,xx) 这样 var newMyList = list.reversed.toList(); //通过toList() 转换格式[香蕉, 苹果] print(newMyList); }
//list的方法
main(){
List list = ['11','22','33'];
list.add('44'); //增加数据 一项
list.addAll(['55','66']); //拼接新数组 类似js数组 concat
list.indexOf('22'); //在数组进行查找 找到返回索引 没找到返回-1 跟js一样
list.remove('22'); //根据具体值在数组中删除
list.removeAt(0); //根据索引删除
list.fillRange(1,3,'aaa'); //1 开始 到3之前 都用'aaa'替换
list.insert(1,'a'); //会在1之后插入'a'
list.insertAll(1,['aa','cc']); //插入数组
// join list转字符串 split 字符串转list 跟js一样
}
Set数据类型
// set 跟js的Set类似 去重后的数组
main(){
var list = new Set();
list.add('a');
var l1 = list.toList(); //直接转换为数组
print(l1);
print(list); {'a'}
var l2 = ['1','2','3']
list.addAll(l2); //讲数组整个加入到set 并且会执行去重操作
print(list);
}
Maps的属性和方法
常用属性
main(){
Map map = {
"name":"沾三"
};
print(map.keys.toList()); //获取所有的key
print(map.values.toList()); //获取所有的value
print(map.isEmpty);
print(map.isNotEmpty);
}
常用方法
main(){ Map map = { "name":"沾三" }; //加入多个map 内容是{} 有点像js的 assign方法 进行对象合并 后面的会把前面的覆盖 map.addAll({ "age":"22", "children":{ "user":"李四", "info":"11" } }); map.remove('age'); //删除数据 //查map中是否有该属性 直能查找一层 print( map.containsValue('11')); print(map);}
遍历集合的方法
for in
// for in item相当于list里面的内容 每次发生变化 遍历list每一项 void main(){ List list = [1,2,3]; for(var item in list){ print(item); }}
forEach
//list 使用forEach
void main(){
List list = [1,2,3];
list.forEach((value){
print('$value');
});
}
//set 中的forEach
void main(){
var list = new Set();
list.add('aaa');
list.forEach((el)=>print(el));
}
//map forEach
void main(){
Map map ={
'name':"张三"
};
map.forEach((key,value)=>print('$key----$value'));
}
map
//map 方法 与js 类似 也是遍历 需要return 数据void main(){ List list = [1,23,4] var newList = list.map((value){ //不能用List 定义变量接受 只能用var return value*2; }); print(newList); // (2,46,8) print(newList.toList());// [2,46,8]}
where
//where 方法 相当于js 的filter 返回满足条件的void main(){ List list = [1,23,4]; var newList = list.where((value){ return value>4; }); print(newList.toList());}
any/every
//any every 类似与js的 some 和every //any 有一个满足条件返回true every 全部满足条件返回truevoid main(){ List list = [1,23,4]; var newList = list.every((value){ return value>4; }); print(newList);}
函数/方法
内置方法 /函数
print()
函数定义/函数格式
/**
自定义方法基本格式
如果不写返回值类型 返回值类型会自己断言
作用域与js 类型 ,直接调用当前作用域和作用域以上 且不能穿透调用
返回类型 方法名称(参数1,参数2,....){
方法体
return 返回值;
}
*/
String printInfo(){
return 'aaa';
}
void main(){
print('调用');
var one = printInfo();
print(one);
}
参数可选
// [] 在形参列表中 作为可选参数 ,可以有多个int getNum(int end,[var start]){ return end;}main(){ var one = getNum(80); print(one);}
带默认参数的方法
int getNum(int end,[int start=10]){ return end+start;}main(){ var one = getNum(80); print(one);}
List 或 Map 同样也可以作为默认值
void doStuff( {List<int> list = const [1, 2, 3], Map<String, String> gifts = const { 'first': 'paper', 'second': 'cotton', 'third': 'leather' }}) { print('list: $list'); print('gifts: $gifts');}
参数命名
int getNum(int end,{int start=10}){ return end+start;}main(){ var one = getNum(80,start:20); //调用的时候 要指定参数名 print(one);}
方法作为参数
void main(){ fn1(){ print('fn1'); } fn2(fn){ fn(); } fn2(fn1);}
箭头函数
//与js的有点区别main(){ List list = [1,2,3]; list.forEach((value)=>print(value)); // => 函数后面只能写一个语句 list.forEach((value)=>{ print(value) //不需要写分号 只能写一个语句 });}
自执行函数
// 跟js的立即执行函数一样((int n ){ print('立即执行函数')})(20)
所有的函数都有返回值。没有显示返回语句的函数最后一行默认为执行 return null
作用域
与js一致,也是全局和局部作用域,变量的作用域在写代码的时候就确定了,大括号内定义的变量只能在大括号内访问
main() { var some = '111'; void todo() { String name = '222'; print(some); } // print(name); //这里访问不到函数内容属性 if (true) { var name = '222'; } print(name) ////这里访问不到函数内容属性}
闭包
与js一致,也是内部函数返回到全局作用域,导致无法销毁
闭包 即一个函数对象,即使函数对象的调用在它原始作用域之外,依然能够访问在它词法作用域内的变量
todo() {
int count = 0;
//如果要返回一个函数 则需要返回一个匿名函数
return () {
return count++;
};
}
main(List<String> args) {
var some = todo();
print(some());
print(some());
print(some());
print(some());
}
类
List Map Set 等都是系统提供的类
自定义类 (与js的类 有点相似)
class Person{
String name = '战三';
int age = 11;
//默认构造函数
Person(){
print('这是构造函数里面的内容,在类初始化会触发');
}
void getInfo(){
print('$name');
//如果是对象属性 需要是{}包裹 表示是一个整体
print('${this.name}-----${this.age}');
}
void setInfo(int val){
//使用this 和 不使用this 的情况是一样的 操作的是同一个属性
age = val;
}
}
void main(){
var one = new Person();
// print(one.name);
// one.getInfo();
one.setInfo(222);
one.getInfo();
}
构造函数简写
//构造函数简写
Person(String name,int age){
this.name = name;
this.age = age;
}
Person(this.name,this.age);
命名构造函数
class Person{
var name;
var age;
Person(this.name,this.age);
//命名构造函数1
Person.now(){
print('调用的now');
}
//命名构造函数2
Person.setUserInfo(String name,int age ){
this.name = name;
this.age = age;
}
Person.some(int age):this(age:0);
void getInfo(){
print('${this.name}----${this.age}');
}
}
void main(){
var p1 = new Person.setUserInfo('张三',222);
p1.getInfo();
}
把类抽离成单独的文件
import 'lib/Person.dart';//把抽离成一个单独的dart 文件 //引入该文件就可以直接使用void main(){ Person p1 = new Person.setUserInfo('张三',22); p1.getInfo();}
类属性和方法私有化
//类的私有属性 和 私有方法//Dart 没有修饰符 对属性/方法进行私有化操作//Dart可以使用 _ 把一个属性/方法变为私有化//而且必须要抽离成一个单独的文件里面才有效果//私有属性或者私有方法 在外部要访问 需要通过间接方法的方式 调用私有属性和调用私有方法import 'lib/Animal.dart';void main(){ Animal doge = new Animal('gigi',22); print(doge.getName()) ; a.execRun();}//Animal.dartclass Animal{ String _name = ''; int age = 0 ; Animal(this._name,this.age); void getInfo(){ print('${this._name}'); } String getName(){ return this._name; } void _run(){ print('这是一个私有方法'); } void execRun(){ d._run(); }}
getter setter修饰符
class Ract{
num height = 0;
num width = 0;
Ract(this.height,this.width);
//通过get / set 修饰符 把自定义的方法 升级为类属性
get area{
return this.height * this.width;
}
set areaHeight(val){
this.height = val;
}
}
void main(){
Ract r = new Ract(10,10);
print('面积:${r.area}'); //直接调用属性就可以
r.areaHeight = 2; //也是直接调用数据修改
print('面积:${r.area}'); //直接调用属性就可以
}
构造函数体运行之前初始化实例变量
class Rect{
num height = 0;
num width = 0;
Rect():height=2,width = 2{
}
num getArea(){
return this.height * this.width;
}
}
void main(){
Rect r = new Rect();
print(r.getArea());
}
this访问类属性和不使用this的区别
this会执行实例,访问的是非静态属性,而不使用this则是使用类的静态属性,静态方法中使用this访问会报错
dart中的静态成员
- 使用static 关键字来实现类级别的变量和函数
- 直接可以通过类名调用该类的属性或者方法
- 静态方法 不能访问非静态成员,非静态方法可以访问静态成员
class Person {
String name = '222';
static int age = 2;
static void test() {
// print(this.age); //静态方法使用this 报错
// print(name); //静态方法不能访问非静态成员
}
void show() {
test(); //非静态方法调用静态方法
print(age); //非静态方法调用静态属性 不能使用this方法静态属性
}
}
void main() {
Person.test();
Person p1 = new Person();
p1.name = '333';
p1.show();
}
对象操作符
- ? 条件运算符 类似js的 ?操作符 有的话才会执行
- as 类型转换
- is 类型判断
- .. 和 ?.. 级联运算符 可以让你在同一个对象上连续调用多个对象的变量或方法。
?..运行在 2.12 和以上的 版本 中可用。
class Person { String name = '11'; int age = 22; void show() { print('${this.name}----${this.age}'); }}
使用?号
main() { Person p = new Person(); p?.show(); //不支持? if (p is Person) { p.name = '李四'; } p.show();}
使用as操作符
main() { var p; p = ''; p = new Person(); (p as Person).show(); //将p的类型推断和转换为Person}
使用级联运算符
main() { Person p1 = new Person(); //原来写法 // p1.name = '22'; // p1.show(); //使用级联操作符 p1 ..name = '22' ..show();}
抛出异常
Dart 代码可以抛出和捕获异常。异常表示一些未知的错误情况,如果异常没有捕获则会被抛出从而导致抛出异常的代码终止执行。
throw UnimplementedError()
捕获异常
捕获异常可以避免异常继续传递(重新抛出异常除外)。捕获一个异常可以给你处理它的机会
try { breedMoreLlamas();} on OutOfLlamasException { buyMoreLlamas();}
对象的封装.继承.多态
封装是指可以把一类客观事物封装成一个类,在类里面抽象他的属性和方法
类的继承
- 子类使用extends关键词 来继承父亲
- 子类会继承父亲里面可见的属性和方法, 但是不会继承构造函数
- 子类能复写父亲的方法 getter和setter
class Person {
String name = '张三';
num age = 22;
void show() {
print('${this.name}----${this.age}');
}
}
class Web extends Person {}
main() {
Web web = new Web();
web.show();
}
类的属性扩展和super使用
class Person {
String name;
num age;
Person(this.name, this.age);
Person.now(this.age, this.name);
void show() {
print('${this.name}----${this.age}');
}
}
class Web extends Person {
//子类扩展自己的属性
String sex = '';
//通过构造函数初始化参数的形式 调用super 给父类传值
//调用super 就是触发父类的构造函数
Web(String name, num age, String sex) : super(name, age) {
this.sex = sex;
}
//调用父类 命名构造函数
Web.now(String name, num age, String sex) : super.now(age, name) {
this.sex = sex;
}
//扩展自己的方法
run() {
print('${this.name}----${this.age}----${this.sex}');
}
}
main() {
Web web = new Web('张三', 12, '女');
web.show();
web.run();
}
覆写父类的方法
class Person {
String name;
num age;
Person(this.name, this.age);
void show() {
print('${this.name}---${this.age}');
}
void work() {
print('work');
}
}
class Web extends Person {
Web(String name, num age) : super(name, age);
run() {
print('run');
}
//重写父类方法 最后加上 @override 表示该方法为重写父类
//方法名与父类一直 即为重写
@override
void show() {
print('姓名:${this.name}---年龄:${this.age}');
}
@override
void work() {
print('${this.name}的工作是写代码');
}
}
main() {
Web web = new Web('李四', 22);
web.show();
web.work();
}
子类调用父类的方法
class Person { String name; num age; Person(this.name, this.age); void work() { print('work'); }}class Web extends Person { Web(String name, num age) : super(name, age); run() { print('run'); //子类中调用父类的属性 print(super.name); //子类中调用父类的方法 super.work(); }}main() { Web web = new Web('李四', 22); web.run();}
重写getter 和setter
class Person { String name = ""; get sex { return '女'; } set setName(val) { this.name = val; }}class Web extends Person { String name = ""; @override get sex { return '男'; } set setName(val) { this.name = val; }}main(List<String> args) { Web web = new Web(); print(web.sex); web.setName = '333'; print(web.name);}
抽象类
dart中的抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口 1.抽象类通过 abstract 关键字类定义 2.Dart 中的抽象方法不能用abstract声明,Dart 中没有方法体的方法称为抽象方法 3.如果子类继承抽象类必须实现里面的抽象方法 4.如果吧抽象类作为接口实现的话必须实现抽象类里面定义的属性和方法 5.抽象类不能被实例化,只有继承它的子类可以
extends抽象类和 implements 的区别: 1.如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类 2.如果只是吧抽象类当做标注的话我们就要用implements实现抽象类
案例:定义一个Animal类 要求他的子类必须包含eat方法
//抽象类
//父类只做约束 只写函数名 不写函数体 这才是规范
//如果写了函数体 那么就是公用属性 会被子类继承
abstract class Animal {
run(); //抽象类不写方法体 只写方法名和实形参列表 就形成方法约束
eat();
//普通函数 子类皆可以使用且不需要子类定义
void show() {
print('我是抽象类的普通函数');
}
}
class Dog extends Animal {
@override
eat() {
print('小狗吃骨头');
}
@override
run() {
print('小狗吃跑');
}
}
class Cat extends Animal {
@override
eat() {
print('小猫吃猫粮');
}
@override
run() {
print('小猫吃跑');
}
}
main() {
Dog dog = new Dog();
dog.eat();
Cat cat = new Cat();
cat.run();
dog.show();
// var a = new Animal(); //抽象类不能直接被实例化
}
多态
- 允许将子类类型的指针赋值给父类类型的指针,同一个函数调用会有不同的效果
- 子类的实例赋值给父类的引用
- 多态是定义一个方法自己不去实现,让继承他的子类去实现,每个子类有不同的表现(重点)
//实际上 父类只做规范和定义需求 表示子类需要实现哪些东西//子类去做父类规定的事情 并且不同的子类 对该方法的实现都不一样 这就是多态abstract class Animal { eat(String name);}class Dog extends Animal { @override eat(String name) { print('小狗吃$name'); }}class Cat extends Animal { @override eat(String name) { print('小猫吃$name'); }}main(List<String> args) { Dog dog = new Dog(); Cat cat = new Cat(); dog.eat('狗粮'); cat.eat('猫粮');}
接口
- dart的接口没有interface关键字定义接口,而是普通类或者抽象类都可以作为接口实现
- 同样使用implements关键字进行实现
- 但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性和方法全都要覆写一遍
- 而因为抽象类可以定义抽象方法,普通类不可以,所以一般要实现java接口那样的方式,一般会使用抽象类,所以使用抽象类定义接口
/*
Db用抽象类作为接口
Mysql MongoDB 使用Db接口
也就是抽象类 只是将属性和方法做了统一规范,归属为一类 可以通用
可以抽离成文件,之前有学过
接口的实现
implements 去继承抽象类(接口) 也叫实现接口,去完成接口定义的事
*/
abstract class Db {
String? name;
add(String name);
}
class Mysql implements Db {
String? name;
Mysql(this.name);
@override
add(String name) {
// TODO: implement add
print('这是mysql数据库打印$name');
}
}
main( ) {
Mysql mysql = new Mysql('name');
mysql.name = '111';
mysql.add('localhost');
}
一个类 实现多个接口
//要实现所有接口的属性
abstract class A {
printA();
}
abstract class B {
printB();
}
class C implements A, B {
@override
printA() {
print('a');
}
@override
printB() {
print('b');
}
}
main() {
C c = new C();
c.printA();
c.printB();
}
mixins
可以使用mixins实现类似多继承的功能,目前支持2.x以上版本
-
作为mixins的类只能继承自Object,不能继承其他类
- 不能使用抽象类
- 继承其他类的后的子类,不能被mixins
- 继承和mixins可以同时使用,可以先继承后mixins
-
作为mixins的类不能有构造函数
-
一个类可以mixins多个mixins类
-
mixins绝不是继承,也不是接口,而是一种全新的特性
class A {
void printA() {
print('a');
}
}
class Person extends A {
String name;
int age;
Person(this.name, this.age);
void printInfo() {
print('${this.name} --- ${this.age}');
}
}
class B {
//写了构造函数也不能被继承
// B(){}
void printB() {
print('b');
}
}
// mixins Person 会报错
// 如果有同名属性或者方法 后mixins的会覆盖前面的
class C extends Person with A, B {
C(String name, int age) : super(name, age);
}
// mixins的实例是什么
// mixins的实例是其超类(父类)的子类型
main(List<String> args) {
C c = new C('张三', 22);
c.printA();
c.printInfo();
//三个都是ture
print(c is A);
print(c is B);
print(c is C);
}
泛型
泛型就是解决类 接口 方法的复用性,以及对不特定数据类型的支持(类型校验)
泛型方法
//返回类型 期望校验类型 传入类型
//三个部分 哪个部分不写 不校验那部分
T getInfoData<T>(T name) {
return name;
}
main(List<String> args) {
getInfoData('name'); //此时没有开启类型校验
getInfoData<String>('name'); //开启类型校验
// getInfoData<String>(1111); //类型与泛型类型不匹配
}
泛型类
class MyList<T> {
List list = <T>[];
void add(T value) {
this.list.add(value);
}
List getList() {
return this.list;
}
}
main(List<String> args) {
//开启泛型
MyList l1 = new MyList<int>();
l1.add(1);
l1.add(222);
l1.add('111'); //这里不行 运行会报错
print(l1.getList());
}
泛型接口
//实现数据缓存的功能:有文件缓存.内存缓存,内存缓存和文件缓存按照接口约束实现 //1.定义一个泛型接口 约束实现它的子类必须有getByKey(key) 和setByKey(key,value) //2.要求setByKey的时候的value的类型和实例化子类的时候指定的类型必须一致abstract class ObjectCache { getbyKey(String key); void setByKey(String key, Object value);}abstract class Cache<T> { getbyKey(String key); void setByKey(String key, T value);}
abstract class Cache<T> {
getbyKey(String key);
void setByKey(String key, T value);
}
class FileCache<T> implements Cache<T> {
@override
getbyKey(Comparable<String> key) {
return null;
}
@override
void setByKey(String key, T value) {
print('我是文件缓存 吧key=${key} value=${value}的数据写入到了文件中!');
}
}
//使用泛型接口
class MemoryCache<T> implements Cache<T> {
@override
getbyKey(String key) {
return null;
}
@override
void setByKey(String key, T value) {
print('我是内存缓存 吧key=${key} value=${value}的数据写入到了内存中!');
}
}
main() {
MemoryCache m = new MemoryCache<Object>();
m.setByKey('m', 'value');
}
Package
-
在dart库中,库的使用时通过import关键字引入的
-
library 指令可以创建一个库,每个dart文件都是一个库,即使没有使用library指令来指定
-
dart抽离成文件的话,不需要单独写export ,dart会自己增加
dart的库主要有三种
-
我们自己定义的库,讲类作为单独的一个文件 前面讲过
import 'lib/xxx.dart' -
系统内置库,dart/flutter的SDK 提供
import 'dart:io'import 'dart:math' -
Pub包管理系统中的库
//包管理库 https://pub.dev/packages https://pub.flutter-io.cn/packages https://pub.dartlang.org/flutter/-
需要在自己的项目根目录建一个pubspec.yaml
-
在pubspec.yaml文件,然后配置名称,描述,依赖等信息
name: qugao description: A new flutter app dependencies: http: ^0.12.0+0.2 date_format: ^2.0.2 environment: sdk: ">=2.10.0 <3.0.0" -
然后运行pub get 获取包下载到本地
-
项目引入库 import 'package:http.dart' as http
-
//使用http库
import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
void main(List<String> arguments) async {
// This example uses the Google Books API to search for books about http.
// https://developers.google.com/books/docs/overview
var url =
'https://fastmock.site/mock/d6595c932da9f203e13525deb8d8eba6/api/getUserIngo';
// Await the http get response, then decode the json-formatted response.
var response = await http.get(url);
if (response.statusCode == 200) {
var jsonResponse =
convert.jsonDecode(response.body) as Map<String, dynamic>;
print(jsonResponse);
} else {
print('Request failed with status: ${response.statusCode}.');
}
}
//使用date_format 库 import 'package:date_format/date_format.dart'; main(List<String> args) { print(formatDate(DateTime(1989, 2, 21), [yyyy, '-', mm, '-', dd])); }
使用本地库
import 'lib/Animal.dart';main() { Animal dog = new Animal<String>('name'); dog.setName('cat'); dog.show();}
使用系统内置库
//使用内置库 发起http请求
import 'dart:convert';
import 'dart:io';
main() async {
var result = await _getDataForApi();
print(result);
}
_getDataForApi() async {
var httpClient = new HttpClient();
var uri = new Uri.https('fastmock.site',
'/mock/d6595c932da9f203e13525deb8d8eba6/api/getUserIngo');
var request = await httpClient.getUrl(uri);
var response = await request.close();
return await response.transform(utf8.decoder).join();
}
解决引入类名重复的问题
import 'lib/Animal.dart';
import 'lib/Animal2.dart' as lib;
main(List<String> args) {
Animal dog = new Animal('dog');
lib.Animal cat = new lib.Animal('cat');
dog.show();
cat.show();
}
异步 async
与js的async 一致
- async 和await 关键字
- 只有async的方法才能使用await关键字
- 如果调用别的async,必须使用await关键字
- async是让方法变成异步
- await 是等待异步方法执行完毕
main() async {
var res = await getAsyncData();
print(res);
}
getAsyncData() {
return 'aaa';
}
部分引入
//meThod.dart
void showInfo() {
print('show');
}
String getInfo() {
return 'aaa';
}
void sea() {
print('sea');
}
默认引入,即全部引入
import 'myMeth.dart';
main() {
show();
var one = getInfo();
print(one);
}
只引入那些 -show关键字
import 'myMeth.dart' show getInfo,sea;
main() {
// showInfo(); //此时该方法不能使用
var one = getInfo();
print(one);
sea();
}
隐藏那些 - hide关键字
import 'myMeth.dart' hide getInfo,sea;
main() {
showInfo(); //此时该方法可能使用
//不能使用
// var one = getInfo();
// print(one);
//sea();
}
flutter笔记
windows上vscode默认没有第三方模拟器的解决方法
-
进入模拟器安装文件的bin目录
-
以夜神为例: 运行命令
nox_adb.exe connect 127.0.0.1:62001 -
下载的东西卡死可以翻墙
启动项目
在配置好模拟器/设备后,在vscode右下角能够看到并可以选择选择设备然后运行命令,启动项目并在设备上安装应用
flutter run
- r键:点击后热加载,也算是重新加载
- p键:显示网格
- o键:切换ios或者android 的预览模式
- q键:退出调试预览模式
通过命令行创建项目
flutter create flutterDemo
目录分析
android //安卓文件目录
ios //ios文件目录
build //打包后的目录
lib //自己开发的文件目录
test //测试文件
pubspec.yaml //项目配置文件 类型npm的package.json
入口文件
lib目录里面都会有一个main.dart文件,这个文件就是flutter的入口文件
void main() => runApp(MyApp()); //代码入口
flutter中实例化类,可以省略new 关键字
main(){
Person p= new Person('aa');
Person p1 = Person('aaa'); // 省略
}
MaterialApp
它封装了应用程序实现Material Design所需要的一些widget,一般作为顶层widget使用 根组件
home 属性 组件的主体部分 可视化部分(主页)
- title属性 标题
- routes属性 路由
- theme属性 颜色主题部分
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: HomeContent(),
),
theme: ThemeData(primarySwatch: Colors.yellow),
);
Scaffold
Material Design布局结构的实现 此类提供了用于显示Drawer,SnackBar和底部sheet的API
- appBar 属性 显示在界面顶部的一个AppBar
- body 属性 当前界面所显示的主要内容 widget
- drawer 属性 抽屉菜单控件
Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: HomeContent(),
)
自定义组件
StatelessWidget 无状态组件 静态组件 是个抽象类
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(
'你好flutter 111',
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 40.0, color: Colors.yellow),
),
);
}
}
Widget 组件
- flutter 所有的东西 都是组件 都是 Widget
- 例如 Text Center 等都是组件
- 给他text组件增加装饰 使用 TextStyle
Center(
child: Text(
'你好flutter 111',
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 40.0, color: Colors.yellow),
),
);