flutter开发环境

由于futter是跨平台开发,而iOS打包又需要Mac电脑,因此推荐使用macOS进行flutter开发。

flutterSDK 2.2.3

官网https://flutter.dev/

推荐开发工具:Android Studio

创建项目

flutter create demo 默认iOS是用swift语言,Android是kotlin语言。

flutter run 运行项目。

变量var

变量var默认是没有类型的,即Null类型。变量可以在运行的过程中赋值不同类型的变量。

  var a;
  print(a);//null
  print(a.runtimeType);//Null

  a = "Hello world";
  print(a);//Hello world
  print(a.runtimeType);//String

  a = 10;
  print(a);//10
  print(a.runtimeType);//int

最终变量final

最终变量只能赋值一次,且在赋值之前是不能使用的。

  final a;

  // 语法错误,赋值之前不能使用
  // print(a.runtimeType);

  a = 10;
  print(a);//10
  print(a.runtimeType);//Int

  // 语法错误,只能赋值一次
  // a = 20;

  // 定义变量的时候一起赋值
  final b = 20;

常量const

定义的时候必须初始化,且不能再次赋值。

  const a = 10;
  print(a);//10
  print(a.runtimeType);//int

num类型

num不是一种类型,而是包含了int和double两种类型。

  //number类型 num不是一种类型,而是包含了int和double两种类型类型
  num a;

  // 语法错误, 使用之前必须赋值
  // print(a);

  a = 10;
  print(a);//10
  print(a.runtimeType);//int

  a = 20.0;
  print(a);//20.0
  print(a.runtimeType);//double

int类型

如果显示的声明为int类型,则不能赋值为double类型的数据

  int a ;
  a = 10;
  a = 30;

  // 语法错误,int不能赋值double类型的数据
  // a = 20.0;

  print(a);//30
  print(a.runtimeType);//int

  // isOdd判断是否为奇数
  var odd = a.isOdd;

  // isEvent判断是否为偶数
  var even = a.isEven;

  print(odd);//false
  print(odd.runtimeType);//bool
  print(even);//true
  print(even.runtimeType);//bool

  // 算术运算符
  // 加法运算符
  print(10 + 2);//12

  // 减法运算符
  print(10 -2);//8

  // 除法运算符
  print(10/3);//3.333333

  // 取模运算符 求余数
  print(10%3);//1

  // 取整运算符~/
  print(10~/3);// 除法取整数部分

double类型

double类型是用户保存小数的,double类型的数据可以再次用整数赋值。虽然可以再次用整数赋值,但是数据还是double数据类型。

 // 语法错误,变量未赋值
 // print(a);
 
  a = 3.14;
  print(a);
  print(a.runtimeType);

  // double类型赋值整数类型的数据
  a = 30;
  a =  20.123;

类型转换

x.toInt()将double类型转成int类型。

d.toDouble()将int类型转成double类型。

  int a = 20;
  double b = 30.4;
  print(a.toDouble());//20.0
  print(a.toDouble().runtimeType);//double

  print(b.toInt());//30
  print(b.toInt().runtimeType);//int

字符串String

  // String类型

  // 字符串可以用双引号
  String str1 = "Hello world";

  // 字符串也可以用单引号
  String str2 = 'Hello flutter';

  // 双引号可以换行,内容会合并,Dart Flutter
  String str3 = "Dart "
    "flutter";

  // 三个单引号
  String str4 = '''Hello
    to
    flutter''';

  // 原始字符串r"",里面的字符串内容会原样输出,比如\n不会被解释成换行
  String str5 = r"hello \n world";

  // 字符串方法

  // 取第一个字符
  var first = str1[0];
  print(first);//H
  print(first.runtimeType);//String

  // 如果超出范围,则闪退,后续的代码都无法继续执行
  // var at100 = str1[100];
  // print(at100);
  // print(at100.runtimeType);

  // 字符串拼接
  var all = str1 + str2;
  print(all);//Hello worldHello flutter
  print(all.runtimeType);//String

  // 字符串重复
  var repeat = str1 * 2;
  print(repeat);//Hello worldHello world
  print(repeat.runtimeType);//String

  // 模板字符串 ${变量} 或者$变量 或者 ${表达式}
  var strWithStr = "${str1} + str2 = ${str1 + str2}";
  print(strWithStr);//Hello world + str2 = Hello worldHello flutter
  print(strWithStr.runtimeType);//String

  // 字符串开头
  print(str1.startsWith("H"));//true

  // 字符串是否以XX结尾
  print(str1.endsWith("world"));

  // 字符串长度
  print(str1.length);//11

可变列表

  // 可变列表
  var list = [1,2,3.14,"Hello"];
  print(list);//[1, 2, 3.14, Hello]
  print(list.runtimeType);//List<Object>
  // 可变列表可以根据索引修改数据
  list[0] = "你好";
  print(list);//[你好, 2, 3.14, Hello]

  // 插入数据
  list.insert(0, "李白");
  print(list);//[李白, 你好, 2, 3.14, Hello]

  print(list.length);//5
  // add的字符在print输出的时候,会根据逗号分隔,如果某个元素本身有逗号,则看起来会多了一个元素,
  list.add("猥琐发育, 别浪");
  print(list);//[李白, 你好, 2, 3.14, Hello, 猥琐发育,别浪]
  print(list.length);//6

  // 删除数据
  list.remove(3.14);
  print(list);//[李白, 你好, 2, Hello, 猥琐发育, 别浪]
  list.removeAt(4);
  print(list);//[李白, 你好, 2, Hello]
  list.removeLast();
  print(list);//[李白, 你好, 2]

不可变列表

  // 不可变列表
  var list = const [1,2,3.14,"Hello"];
  print(list);//[1, 2, 3.14, Hello]
  print(list.runtimeType);//List<Object>

  // 语法错误,因为list指向的是常量区内存
  // list[0] = "Hello";

  // list本身是可以变的
  list = [1,4,100];
  print(list);

map和不可变map

  // map 保存键值对,
  //
  // 常用的key为String类型
  var map = {"name":"阿珂","职业":"专业打野30年"};
  print(map);//{name: 阿珂, 职业: 专业打野30年}
  print(map.runtimeType);//_InternalLinkedHashMap<String, String>

  // 如果value为多种数据类型,则泛型为Object
  var map1 = {"name":"妲己","age":18};
  print(map1);//{name: 妲己, age: 18}
  print(map1.runtimeType);//<String, Object>

  // 如果key为多种数据类型,则key对应的泛型也是Object,且类型变成了LinkedMap
  var map2 = {1:"蒙恬","2":"老夫子",3:2022};
  print(map2);//{1: 蒙恬, 2: 老夫子, 3: 2022}
  print(map2.runtimeType);//LinkedMap<Object, Object>

  //不可变的map
  var map3 = const {1:23};
  print(map3);//{1: 23}
  print(map3.runtimeType);//ImmutableMap<int, int>
  // 语法错误Cannot modify unmodifiable map
  // map3[2] = 20;
  // 变量是可变的,但是变量对应的内存区间是不可变的

  // 语法错误,如果变量声明的时候初始化,则数据类型必须保持一致,比如上面的key和valye都是int类型
  map3 = {1:222};
  map3[0] = 19;

  // 常用方法
  // 键值对的数量
  print(map2.length);//3
  // 获取所有的key
  print(map2.keys);//(1, 2, 3)
  // 获取所有的值
  print(map2.values);//(蒙恬, 老夫子, 2022)
  print(map2.values.runtimeType);//_JSMapIterable<Object>

list转map

  // list
  var list = ["阿珂","猴子","镜"];

  // map
  var map = {"name":"阿珂","age":"18"};

  // list转map, 通过输出类型发现该map并没有key对应的泛型.
  // key为对应的索引值,value为list中的值
  var listToMap = list.asMap();
  print(listToMap);//{0: 阿珂, 1: 猴子, 2: 镜}
  print(listToMap.runtimeType);//ListMapView<String>

??=??

  // ??= 如果有值,则不进行操作,如果没有值,则进行赋值操作
  // a??b 条件表达式, 如果a不为null,则返回a;如果a为null,则返回b

  // ??=
  var a ;
  print(a);//null
  a ??= 10;
  print(a);//10

  // 此时因为a有值了,所以赋值无效
  a ??= 20;
  print(a);//10

  // ??
  var b;
  var b1 = b??100;
  print(b1);//100
  print(b1.runtimeType);//int

  b = 20;
  b1 = b??100;
  print(b1);//20
  print(b1.runtimeType);//int

函数

定义函数的格式。

返回值类型 函数名称(参数列表){
  方法体
}

定义无参数无返回值的函数。

void main() {
  // 使用函数的时候,函数名称加括号
 sayHello();
 sayHello1();
}

// 定义函数
void sayHello(){
  print("Hello");
}

如果函数体只有一行代码,可以使用箭头函数

void main()=> sayHello1();
// 如果函数只有一句,可以使用箭头
void sayHello1() => print("Hello");

带参数和返回值的函数。

void main() {
  var res = sum(10, 20);
  print(res);

  // 语法错误。参数只能是int类型
  // var res1 = sum(10.0 , 11.2);
  // print(res1);

  var res2 = sum1(10.2, 20.3);
  print(res2);//30.5
  print(res2.runtimeType);//double

  // int类型可以自动类型转成double,如果整数可以保存,则返回结果会被优化成整数
  var res3 = sum1(10.0, 20.0);
  print(res3);//30
  print(res3.runtimeType);//int

  // 两个double类型的值返回值是int。注意
  var res4 = sum1(10.3, 20.7);
  print(res4);//31
  print(res4.runtimeType);//int

}

泛型函数,不指定类型,只要符合语法格式就可以。

void main() {
  var res1 = sum(10, 20);
  var res2 = sum(10.1 , 20);
  var res3 = sum(10.2 , 19.3);
  var res4 = sum("hello", " world");
  print(res1);//30
  print(res1.runtimeType);//int
  print(res2);//30.1
  print(res2.runtimeType);//double
  print(res3);//29.5
  print(res3.runtimeType);//double
  print(res4);//hello world
  print(res4.runtimeType);//String
}

// 只要该类型支持+运算就可以传递
sum( a, b) {
  return a + b;
}

可选参数

void main() {
  optionFunction(10);
  optionFunction(10,b:3);
  optionFunction(10,c:3);
  optionFunction(10,b:3,c:4);

}

// 可选参数

// int类型不能为空
// void optionFunction(int a,{int b, int c}){
void optionFunction(int a,{var b, var c}){
  b ??= 0;
  c ??= 0;
  print("total is ${a + b + c}");
}

可变参数

void main() {
  changeableFunction(10);
  changeableFunction(10,20);
  changeableFunction(10,20,30);
  // 最多只能参数规定的数量
  // changeableFunction(10,20,30,40);
}

// 可变参数
void changeableFunction(int a,[int b = 0, int c = 0]){
  print("total is ${a + b + c}");
}

闭包:闭包是一个特殊的函数,可以保存上下文

void main() {
  var closure = func1();
  closure();//11
  closure();//12
  closure();//13
}

// 闭包 , 可以保存上下文
func1(){
  int a = 10;
  return (){
    a++;
    print(a);
  };
}

面向对象

class声明类。

void main() {
 var p = Person();
 p.name = "小白";
 p.age = 18;
 p.des();
}

// 面向对象
class Person {
  String? name;
  int? age;

  des(){
    print("name is $name age is $age");
  }
}

默认构造函数

void main() {
 var p = Person();
 p.name = "小白";
 p.age = 18;
}

// 面向对象
class Person {
  String? name;
  int? age;

  // 默认构造函数,
  Person(){
    print("我是构造函数");
  }
}

自定义构造函数,构造函数只能有一个。

void main() {
 var p = Person("李白",18);
 p.name = "小白";
 p.age = 18;
}

// 面向对象
class Person {
  String? name;
  int? age;

  Person(String name, int age){
    this.name = name;
    this.age = age;
  }
}

构造函数的简介形式

void main() {
 var p = Person("李白",18);
 p.name = "小白";
 p.age = 18;
}

// 面向对象
class Person {
  String? name;
  int? age;

 Person(this.name, this.age);
}

构造函数只能有一个,但是命名构造函数可以有多个

void main() {
 var p = Person("李白",13,"打野");
 p.name = "小白";
 p.age = 18;

 var jungle = Person.assassin();
 jungle.name = "兰陵王";
 jungle.age = 20;

 var middle = Person.master();
 middle.name = "安其拉";
 middle.age = 10;
}

// 面向对象
class Person {
  String? name;
  int? age;
  String?job;
  Person(this.name, this.age, this.job);

  // 命名构造函数可以有多个
  Person.assassin(){
    this.job = "刺客";
  }
  Person.master(){
    this.job = "法师";
  }
}

类和文件

//student.dart
class Student{
  // 成员变量下划线开头为私有成员变量
  int? _age;

  String? name;

  // 方法名称下划线开头为私有方法
  void _innerPrint(){
    print("我是内部方法");
  }
  void commonPrint(){
    print("我是通用方法");
  }
}

void insideMethod(){
  Student s = Student();
  // 同一个文件可以访问私有成员变量
  s._age = 100;
  s.name = "张三丰";
  // 同一个文件可以访问私有方法
  s._innerPrint();
  s.commonPrint();
}

// main.dart
import "student.dart";
void main() {
 insideMethod();

 var s = Student();
 // 语法错误 无法访问私有成员变量
 // s._age = 10;

 // 语法错误,无法访问私有成员方法
 // s._innerPrint()
 s.name = "大白";
}

计算属性:获取值使用get,设置值使用set。

void main() {
 var s = Person();

 // 计算属性不能使用函数的形式传递参数调用
 // s.setAge(100);
 s.setAge = 20;
 print("age is ${s.getAge}");
}

// 面向对象
class Person {
  int? age;
  // 计算属性
  // 计算属性使用关键字+属性名称,注意此时没有括号
  get getAge{
    return this.age;
  }
  set setAge(value){
    this.age = value;
  }
}

默认初始化

void main() {
  var s = Person();
  print("${s.age} ${s.height}");
}

// 面向对象
class Person {
  int? age;
  int? height;
  Person():age=10,height=108{

  }
}

静态属性和静态方法:都是属于类,不属于对象。

void main() {
  var s = Person();

  // 语法错误:静态属性不属于对象
  // s.maxAge = 30;
  Person.run();
  Person.maxAge = 200;
  Person.run();

}

// 面向对象
class Person {
  // static 声明静态属性
  static int maxAge = 130;
  int? age;
  int? height;
  // 类方法使用static
  static void run(){
    print(maxAge);
  }
}

对象操作符1: 条件运算符? t:如果对象不为空则调用方法,否则啥也不做。

void main() {
  var p;
  // 语法错误:对象是null,不能使用run方法
  // p.run();

  // 使用问号操作符,如果对象不存在,则不会调用方法
  p?.run();
  
  p = Person();
  // 此时p不为空,可以调用该方法
  p?.run();
}

// 面向对象
class Person {
  void run(){
    print("跑呀跑");
  }
}

对象操作符2:连接运算符..

void main() {
  var p = Person();
  p.age = 20;
  p.height = 170;
  p.run();

  // 使用连接..可以在一行多次给属性赋值或者调用方法
  var p1 = Person();
  p1..run()..height=30..age=100..run();

  // 也可以分开多行
  var p2 = Person();
  p1..run()
    ..height=30
    ..age=100
    ..run();
}

对象操作符3: 类型判断is

// 3和4可以打印
void main() {
  var p;
  if (p is Person) {
    print("1p is person");
  }
  if (p is Object){
    print("2p is Object");
  }
  p = Person();
  if (p is Person) {
    print("3p is person");
  }
  if (p is Object){
    print("4p is Object");
  }
}

对象操作符:as类型转换。

void main() {
  var p = Object();
  // p.run();

  // 运行错误
  // (p as Person).run();
  p = Person();
  print(p.runtimeType);//Person
  // 由于p定义的时候直接初始化,因为类型已经确定,Object没有run方法,因此编译报错。虽然runtimeType是Person,但是本质还是Object对象类型
  // p.run();
  (p as Person).run();

  // 但是如果添加了一个判断,则又可以编译通过
  if (p is Person){
    p.run();
  }
}

class Person {
  void run(){
    print("person run");
  }
}

初始化列表: 可以给final赋值,数据校验。

void main() {
  var p = Person(100,200);
}

class Person {
  int age;
  final int maxAge;

  // 初始化列表
  Person(this.age,int max): maxAge=max,assert(max >0),assert(age > 0) {
  }
}

单例1: 工厂方法

void main() {
  var p = Person();
  var p1 = Person();
  if(p == p1){
    print("是同一个对象");
  }
}

class Person {

  // 定义一个私有的命名构造函数
  Person._onlyone();

  // 定义一个静态变量
  static final _instance = Person._onlyone();

  factory Person(){
    return _instance;
  }
}

单例2:直接使用静态变量

void main() {
  var p = Person.instance;
  var p1 = Person.instance;
  if(p == p1){
    print("是同一个对象");
  }
}

class Person {
  static final instance = Person();
}

单例3:因此静态变量,通过静态方法获取

void main() {
  var p = Person.instance();
  var p1 = Person.instance();
  if(p == p1){
    print("是同一个对象");
  }
}

class Person {
  static final _instance = Person();
  static instance(){
    return _instance;
  }
}

单例4:通过计算属性获取

void main() {
  var p = Person.instance;
  var p1 = Person.instance;
  if(p == p1){
    print("是同一个对象");
  }
}

class Person {
  static final _instance = Person();
  static get instance{
    return _instance;
  }
}

继承:子类拥有父类的成员变量和成员方法

void main() {
  var s = Student();
  s.run();
  s.show();
}

class Person {
  int? age;
  void run(){
    print("person run");
  }
  void show(){
    print("person show");
  }
}
//属性和方法都是可以继承的,也可以被重写
class Student extends Person{
  @override
  void show() {
    // TODO: implement show
    print("Student show");
  }
}

抽象类:用于定义接口,不能直接初始化。

void main() {
  People s = Student();
  s.run();

  Doctor d = Doctor();
  d.run();
  d.speak();
}

// abstract class用于定义抽象类,抽象类不能直接初始化
abstract class People{
  void run();
}

abstract class MakeVoice{
  void speak();
}

class Student extends People{
  @override
  void run() {
    print("Student run");
  }
}


// 可以实现多个抽象类
class Doctor implements People,MakeVoice{
  @override
  void speak() {
    print("Doctor speak");
  }

  @override
  void run() {
    print("Doctor run");
  }
}

maxin:可以实现多继承,但是被继承的只能是Object的子类,被继承的类不能实现构造方法。

void main() {
  Instance a = Instance();
  a.a();
  a.b();
  a.c();
}

class A{
  a() => print("a");
}
class B{
  a() => print("b class a");
  b() => print("b");
}
class C{
  c() => print("c");
  a() => print("c class a");
}

运算符重载

void main() {
  Student s = Student(20);
  Student s1 = Student(18);
  Object o = Object();
  print(s > s1);
  print(s == s1);
  print(s < s1);
  print(s > s1);

}

class Student{
  int age;
  Student(this.age);

  @override
  bool operator == (Object other) {
    if (other is Student){
      return this.age == other.age;
    }
    return false;
  }

  bool operator > (Student other) {
    return this.age > other.age;
  }

  bool operator < (Student other) {
    return this.age < other.age;
  }

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

推荐阅读更多精彩内容