flutter简易教程

跟Java等很多语言不同的是,Dart没有public protected private等关键字,如果某个变量以下划线 _ 开头,代表这个变量在库中是私有的。Dart中变量可以以字母或下划线开头,后面跟着任意组合的字符或数字

变量

变量定义

以下代码是Dart中定义变量的方法:

main() {  var a = 1;
  int b = 10;  String s = "hello";
  dynamic c = 0.5;
}
复制代码

你可以明确指定某个变量的类型,如int bool String,也可以用var或 dynamic来声明一个变量,Dart会自动推断其数据类型。

变量的默认值

注意:没有赋初值的变量都会有默认值null

final和const

如果你绝不想改变一个变量,使用final或const,不要使用var或其他类型,一个被final修饰的变量只能被赋值一次,一个被const修饰的变量是一个编译时常量(const常量毫无疑问也是final常量)。可以这么理解:final修饰的变量是不可改变的,而const修饰的表示一个常量。

注意:实例变量可以是final的但不能是const的

下面用代码说明:

var count = 10; 
final Num = count;  // final 只能赋值一次const Num1 = 10; // const赋值必须是编译时常量复制代码

final和const的区别:

区别一:final 要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而 const 要求在声明时初始化,并且赋值必需为编译时常量。

区别二:final 是惰性初始化,即在运行时第一次使用前才初始化。而 const 是在编译时就确定值了。

内建数据类型

Dart有如下几种内建的数据类型:

  • numbers

  • strings

  • booleans

  • lists(或者是arrays)

  • maps

  • runes(UTF-32字符集的字符)

  • symbols 下面用一段代码来演示以上各类数据类型:

main() {  // numbers
  var a = 0;
  int b = 1;
  double c = 0.1;  // strings
  var s1 = 'hello';
  String s2 = "world";  // booleans
  var real = true;
  bool isReal = false;  // lists
  var arr = [1, 2, 3, 4, 5];  List<String> arr2 = ['hello', 'world', "123", "456"];  List<dynamic> arr3 = [1, true, 'haha', 1.0];  // maps
  var map = new Map();
  map['name'] = 'zhangsan';
  map['age'] = 10;
  Map m = new Map();
  m['a'] = 'a';  //runes,Dart 中 使用runes 来获取UTF-32字符集的字符。String的 codeUnitAt and codeUnit属性可以获取UTF-16字符集的字符
  var clapping = '\u{1f44f}';  print(clapping); // 打印的是拍手emoji的表情

  // symbols
  print(#s == new Symbol("s")); // true}
复制代码

函数

函数的返回值

Dart是一个面向对象的编程语言,所以即使是函数也是一个对象,也有一种类型Function,这就意味着函数可以赋值给某个变量或者作为参数传给另外的函数。虽然Dart推荐你给函数加上返回值,但是不加返回值的函数同样可以正常工作,另外你还可以用=>代替return语句,比如下面的代码:

// 声明返回值int add(int a, int b) {  return a + b;
}// 不声明返回值add2(int a, int b) {  return a + b;
}// =>是return语句的简写add3(a, b) => a + b; 

main() {
  print(add(1, 2)); // 3
  print(add2(2, 3)); // 5
  print(add3(1, 2)); // 3}
复制代码

命名参数、位置参数、参数默认值

命名参数

sayHello({String name}) {  print("hello, my name is $name");
}

sayHello2({name: String}) {  print("hello, my name is $name");
}main() {
  // 打印 hello, my name is zhangsan
  sayHello(name: 'zhangsan');

  // 打印 hello, my name is wangwu
  sayHello2(name: 'wangwu');
}
复制代码

可以看到,定义命名参数时,你可以以 {type paramName} 或者 {paramName: type} 两种方式声明参数,而调用命名参数时,需要以 funcName(paramName: paramValue) 的形式调用。

命名参数的参数并不是必须的,所以上面的代码中,如果调用sayHello()不带任何参数,也是可以的,只不过最后打印出来的结果是:hello, my name is null,在Flutter开发中,你可以使用@required注解来标识一个命名参数,这代表该参数是必须的,你不传则会报错,比如下面的代码:

const Scrollbar({Key key, @required Widget child})
复制代码

位置参数

使用中括号[]括起来的参数是函数的位置参数,代表该参数可传可不传,位置参数只能放在函数的参数列表的最后面,如下代码所示:

sayHello(String name, int age, [String hobby]) { // 位置参数可以有多个,比如[String a, int b]
  StringBuffer sb = new StringBuffer();
  sb.write("hello, this is $name and I am $age years old");  if (hobby != null) {
    sb.write(", my hobby is $hobby");
  }
  print(sb.toString());
}

main() {  // hello, this is zhangsan and I am 20 years old
  sayHello("zhangsan", 20);  // hello, this is zhangsan and I am 20 years old, my hobby is play football
  sayHello("zhangsan", 20, "play football");
}
复制代码

参数默认值

你可以为命名参数或者位置参数设置默认值,如下代码所示:

// 命名参数的默认值int add({int a, int b = 3}) { // 不能写成:int add({a: int, b: int = 3})
  return a + b;
}// 位置参数的默认值int sum(int a, int b, [int c = 3]) {  return a + b + c;
}
复制代码

main()函数

不论在Dart还是Flutter中,必须都需要一个顶层的main()函数,它是整个应用的入口函数,main()函数的返回值是void,还有一个可选的参数,参数类型是List<String>。

函数作为一类对象

你可以将一个函数作为参数传给另一个函数,比如下面的代码:

printNum(int a) {  print("$a");
}

main() {  //  依次打印:
  //  1
  //  2
  //  3
  var arr = [1, 2, 3];
  arr.forEach(printNum);
}
复制代码

你也可以将一个函数赋值给某个变量,比如下面的代码:

printNum(int a) {  print("$a");
}

main() {  var f1 = printNum;  Function f2 = printNum;  var f3 = (int a) => print("a = $a");
  f1(1);
  f2(2);
  f3(6);
}
复制代码

匿名函数

大多数函数都是有名称的,比如main() printName()等,但是你也可以写匿名函数,如果你对Java比较熟悉,那下面的Dart代码你肯定也不会陌生:

test(Function callback) {
  callback("hello");
}

main() {
  test((param) {    // 打印hello
    print(param);
  });
}
复制代码

匿名函数类似于Java中的接口,往往在某个函数的参数为函数时使用到。

函数返回值

所有的函数都有返回值,如果没有指定return语句,那么该函数的返回值为null。

运算符

Dart中的运算符与Java中的类似,比如++a a == b b ? a : b,但是也有一些与Java不太一样的运算符,下面用代码说明:

main() {  // 与Java相同的运算符操作

  int a = 1;
  ++a;
  a++;  var b = 1;  print(a == b);  // false
  print(a * b); // 3
  bool real = false;
  real ? print('real') : print('not real'); // not real
  print(real && a == b); // false
  print(real || a == 3); // true
  print(a != 2); // true
  print(a <= b); // false
  var c = 9;
  c += 10;  print("c = $c"); // c = 19
  print(1<<2); // 4

  // 与Java不太一样的运算符操作

  // is运算符用于判断一个变量是不是某个类型的数据
  // is!则是判断变量不是某个类型的数据
  var s = "hello";  print(s is String); // true
  var num = 6;  print(num is! String); // true

  // ~/才是取整运算符,如果使用/则是除法运算,不取整
  int k = 1;
  int j = 2;  print(k / j); // 0.5
  print(k ~/ j); // 0

  // as运算符类似于Java中的cast操作,将一个对象强制类型转换
  (emp as Person).teach();  // ??=运算符 如果 ??= 运算符前面的变量为null,则赋值,否则不赋值
  var param1 = "hello", param2 = null;
  param1 ??= "world";
  param2 ??= "world";  print("param1 = $param1"); // param1 = hello
  print("param2 = $param2"); // param2 = world

  // ?.运算符
  var str1 = "hello world";  var str2 = null;  print(str1?.length); // 11
  print(str2?.length); // null 
  print(str2.length); // 报错}
复制代码

…运算符(级联操作)

如果你对Java中的建造者模式比较熟悉的话,Dart中的…运算符也很好理解,先看下面的代码:

class Person {
  eat() {    print("I am eating...");
  }

  sleep() {    print("I am sleeping...");
  }

  study() {    print("I am studying...");
  }
}

main() {  // 依次打印
  //  I am eating...
  //  I am sleeping...
  //  I am studying...
  new Person()..eat()
      ..sleep()
      ..study();
}
复制代码

可以看到,使用…调用某个对象的方法(或者成员变量)时,返回值是这个对象本身,所以你可以接着使用…调用这个对象的其他方法,这不就类似于Java中的建造者模式,每次build某个属性时,都返回一个this对象吗。

控制流程

if / else switch for /while try / catch语句跟Java中都类似,try / catch语句可能稍有不同,下面用一段代码说明:

main() {  // if else语句
  int score = 80;  if (score < 60) {    print("so bad!");
  } else if (score >= 60 && score < 80) {    print("just so so!");
  } else if (score >= 80) {    print("good job!");
  }  // switch语句
  String a = "hello";  // case语句中的数据类型必须是跟switch中的类型一致
  switch (a) {    case "hello":      print("haha");      break;    case "world":      print("heihei");      break;    default:      print("WTF");
  }  // for语句
  List<String> list = ["a", "b", "c"];  for (int i = 0; i < list.length; i++) {    print(list[i]);
  }  for (var i in list) {    print(i);
  }  // 这里的箭头函数参数必须用圆括号扩起来
  list.forEach((item) => print(item));  // while语句
  int start = 1;
  int sum = 0;  while (start <= 100) {
    sum += start;
    start++;
  }  print(sum);  // try catch语句
  try {    print(1 ~/ 0);
  } catch (e) {    // IntegerDivisionByZeroException
    print(e);
  }  try {    1 ~/ 0;
  } on IntegerDivisionByZeroException { // 捕获指定类型的异常
    print("error"); // 打印出error
  } finally {    print("over"); // 打印出over
  }
}
复制代码

类(Class)

类的定义与构造方法

Dart中的类没有访问控制,所以你不需要用private, protected, public等修饰成员变量或成员函数,一个简单的类如下代码所示:

class Person {  String name;
  int age;  String gender;
  Person(this.name, this.age, this.gender);
  sayHello() {
    print("hello, this is $name, I am $age years old, I am a $gender");
  }
}
复制代码

上面的Person类中有3个成员变量,一个构造方法和一个成员方法,看起来比较奇怪的是Person的构造方法,里面传入的3个参数都是this.xxx,而且没有大括号{}包裹的方法体,这种语法是Dart比较独特而简洁的构造方法声明方式,它等同于下面的代码:

Person(String name, int age, String gender) {    this.name = name;    this.age = age;    this.gender = gender;
}
复制代码

要调用Person类的成员变量或成员方法,可以用下面的代码:

var p = new Person("zhangsan", 20, "male");
  p.sayHello(); // hello, this is zhangsan, I am 20 years old, I am a male
  p.age = 50;
  p.gender = "female";
  p.sayHello(); // hello, this is zhangsan, I am 50 years old, I am a female复制代码

类除了有跟类名相同的构造方法外,还可以添加命名的构造方法,如下代码所示:

class Point {
  num x, y;
  Point(this.x, this.y);  // 类的命名构造方法
  Point.origin() {
    x = 0;
    y = 0;
  }
}

main() {  // 调用Point类的命名构造方法origin()
  var p = new Point.origin();  var p2 = new Point(1, 2);
}
复制代码

Dart中使用extends关键字做类的继承,如果一个类只有命名的构造方法,在继承时需要注意,如下代码:

class Human {  String name;
  Human.fromJson(Map data) {
    print("Human's fromJson constructor");
  }
}class Man extends Human {
  Man.fromJson(Map data) : super.fromJson(data) {
    print("Man's fromJson constructor");
  }
}
复制代码

由于Human类没有默认构造方法,只有一个命名构造方法fromJson,所以在Man类继承Human类时,需要调用父类的fromJson方法做初始化,而且必须使用Man.fromJson(Map data) : super.fromJson(data)这种写法,而不是像Java那样将super写到花括号中。

有时候你仅仅只是在某个类的构造方法中,调用这个类的另一个构造方法,你可以这么写:

class Point {
  num x, y;
  Point(this.x, this.y);  // 命名构造方法调用了默认的构造方法
  Point.alongXAxis(num x) : this(x, 0);
}
复制代码

类的成员方法

一个类的成员方法是一个函数,为这个类提供某些行为。上面的代码中已经有了一些类的成员方法的定义,这些定义方式跟Java很类似,你可以为某个类的成员变量提供getter/setter方法,如下代码:

class Rectangle {
  num left, top, width, height;  // 构造方法传入left, top, width, height几个参数
  Rectangle(this.left, this.top, this.width, this.height);  // right, bottom两个成员变量提供getter/setter方法
  num get right => left + width;  set right(num value) => left = value - width;
  num get bottom => top + height;  set bottom(num value) => top = value - height;
}
复制代码

抽象类和抽象方法

使用abstract修饰一个类,则这个类是抽象类,抽象类中可以有抽象方法和非抽象方法,抽象方法没有方法体,需要子类去实现,如下代码:

abstract class Doer {  // 抽象方法,没有方法体,需要子类去实现
  void doSomething();  // 普通的方法
  void greet() {
    print("hello world!");
  }
}class EffectiveDoer extends Doer {  // 实现了父类的抽象方法
  void doSomething() {
    print("I'm doing something...");
  }
}
复制代码

运算符重载

Dart中有类似于C++中的运算符重载语法,比如下面的代码定义了一个向量类,重载了向量的+ -运算:

class Vector {
  num x, y;
  Vector(this.x, this.y);
  Vector operator +(Vector v) => new Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => new Vector(x - v.x, y - v.y);
  printVec() {
    print("x: $x, y: $y");
  }
}

main() {
  Vector v1 = new Vector(1, 2);
  Vector v2 = new Vector(3, 4);
  (v1 - v2).printVec(); // -2, -2
  (v1 + v2).printVec(); // 4, 6}
复制代码

枚举类

使用enum关键字定义一个枚举类,这个语法跟Java类似,如下代码:

enum Color { red, green, blue }
复制代码

mixins

mixins是一个重复使用类中代码的方式,比如下面的代码:

class A {
  a() {
    print("A's a()");
  }
}class B {
  b() {
    print("B's b()");
  }
}// 使用with关键字,表示类C是由类A和类B混合而构成class C = A with B;

main() {
  C c = new C();
  c.a(); // A's a()
  c.b(); // B's b()}
复制代码

静态成员变量和静态成员方法

// 类的静态成员变量和静态成员方法class Cons {  static const name = "zhangsan";  static sayHello() {    print("hello, this is ${Cons.name}");
  }
}

main() {
  Cons.sayHello(); // hello, this is zhangsan
  print(Cons.name); // zhangsan}
复制代码

泛型(Generics)

Java和C++语言都有泛型,Dart语言也不例外,使用泛型有很多好处,比如:

正确指定泛型类型会产生更好的生成代码。 泛型可以减小代码的复杂度

Dart内置的数据类型List就是一个泛型数据类型,你可以往List中塞任何你想的数据类型比如整型、字符串、布尔值等 关于Dart更多的泛型知识点,可以查看这里。

Dart库(Libraries)

Dart目前已经有很多的库提供给开发者,许多功能不需要开发者自己去实现,只需要导入对应的包即可,使用import语句来导入某个包,比如下面的代码:

import 'dart:html';
复制代码

如果你想导入自己写的某个代码文件,使用相对路径即可,例如当前有一个demo.dart文件,跟该文件同级目录下有个util.dart文件,文件代码如下:

// util.dart文件内容int add(int a, int b) {  return a + b;
}
复制代码

在demo.dart文件中如果要引用util.dart文件,使用下面的方式导入:

// demo.dartimport './util.dart';

main() {
  print(add(1, 2));
}
复制代码

你可以使用as关键字为导入的某个包设置一个前缀,或者说别名,比如下面的代码:

import 'package:lib1/lib1.dart';import 'package:lib2/lib2.dart' as lib2;// Uses Element from lib1.Element element1 = Element();// Uses Element from lib2.lib2.Element element2 = lib2.Element();
复制代码

你也可以在导入包时使用show hide关键字来导入某个包中的部分功能,比如下面的代码:

// 只导入fooimport 'package:lib1/lib1.dart' show foo;// 导入除了foo的所有其他部分import 'package:lib2/lib2.dart' hide foo;
复制代码

导入包时使用deferred as可以让这个包懒加载,懒加载的包只会在该包被使用时得到加载,而不是一开始就加载,比如下面的代码:

import 'package:greetings/hello.dart' deferred as hello;
复制代码

异步

Dart提供了类似ES7中的async await等异步操作,这种异步操作在Flutter开发中会经常遇到,比如网络或其他IO操作,文件选择等都需要用到异步的知识。 async和await往往是成对出现的,如果一个方法中有耗时的操作,你需要将这个方法设置成async,并给其中的耗时操作加上await关键字,如果这个方法有返回值,你需要将返回值塞到Future中并返回,如下代码所示:

Future checkVersion() async {  var version = await lookUpVersion();  // Do something with version}
复制代码

下面的代码使用Dart从网络获取数据并打印出来:

import 'dart:async';import 'package:http/http.dart' as http;

Future<String> getNetData() async{
  http.Response res = await http.get("http://www.baidu.com");  return res.body;
}

main() {
  getNetData().then((str) {
    print(str);
  });
}

原文地址:https://www.cnblogs.com/aibabel/p/11366304.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要讲解了“FlutterComponent动画的显和隐怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究...
这篇文章主要讲解了“flutter微信聊天输入框功能如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“f...
本篇内容介绍了“Flutter之Navigator的高级用法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
这篇文章主要介绍“Flutter怎么使用Android原生播放器”,在日常操作中,相信很多人在Flutter怎么使用Android原生播放器问题上存在疑惑,小编查阅了各式资料,整...
Flutter开发的android端如何修改APP名称,logo,版本号,具体的操作步骤:修改APP名称找到文件:android\\app\\src\\main\\AndroidManifest.xml
Flutter路由管理初识路由概念一.路由管理1.1.Route1.2.MaterialPageRoute1.3.Navigator1.4.路由传值1.5 命名路由1.6.命名路由参数传递1.7.适配二、路由钩子三、onUnknownRoute四、结尾初识路由概念路由的概念由来已久,包括网络路由、后端路由,到现在广为流行的前端路由。无论路由的概念如何应用,它的核心是一个路由映射表。比如:名字 detail 映射到 DetailPage 页面等。有了这个映射表之后,我们就可以方便的根据名字来完成路由的转发
前提:针对Android开发者(windows系统下),已安装Git,AndroidStudio(建议4.0+版本)一.下载Flutter SDK地址:https://flutter.dev/docs/development/tools/sdk/releases,在 Stable channel (Windows)里面下最新版本即可。Flutter的渠道版本会不停变动,请以Flutter官网为准。在中国,要想正常获取安装包列表或下载安装包,可能需要翻墙,也可以去Flutter github项目下去下载安
一、变量变量是一个引用,根据Dart中“万物皆对象”原则,即变量存储的都是对象的引用,或者说它们都是指向对象。1.1.声明变量://1.不指定类型var name = 'aaa';//2.明确指定类型String name = 'aaa';因为有类型推导,所以两种实现效果一样,官方推荐在函数内的本地变量尽量使用var声明。在变量类型并不明确的情况下,可以使用dynamic关键字//3.使用dynamic关键字dynamic name = 'aaa';1.2.默认值未初始化的变量
前言Flutter2.0发布不久,对web的支持刚刚进入stable阶段。初学几天,构建web应用时候碰到一些问题,比如中文显示成乱码,然后加载图片出现图片跨域问题:Failed to load network image...Trying to load an image from another domain?1.开启web端构建:使用下面这个命令才可以开启Web端构建的支持flutter config --enable-web提示我们:重新启动编辑器,以便它们读取新设置。2.重
一.Flutter打Android release包的步骤:1.为项目创建一个.jks签名文件(很简单,跳过)2.创建一个文件key.properties,直接复制下面key.properties位置如图:在里面输入一下内容:storePassword=iflytekkeyPassword=iflytekkeyAlias=teachingmachinestoreFile=E:/teacher/app/keys/TeachingMachine.jks输入你自己的passwork以及
1 问题Android原生向js发消息,并且可以携带数据2 实现原理Android原生可以使用RCTEventEmitter来注册事件,然后这里需要指定事件的名字,然后在js那端进行监听同样事件的名字监听,就可以收到消息得到数据Android注册关键代码reactContext.getJSModule(DeviceEventManagerModule.RCT...
1 Flexbox布局1) flexDirection 可以决定布局的主轴,子元素是应该沿着水平轴(row)方向排列,还是沿着竖直轴(column)方向排列2) justifyContent 决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row,则次轴方向为column)的排列方式 有flex-start、center、flex-end、space-around...
1 实现的功能在网上看React Native文档,我特码就想实现一个页面到另外一个页面的跳转,然后另外一个页面怎么获取参数,特么没找到一个说清楚的,要么太复杂,要么说了不理解,下面是我自己写的一个App.js文件,实现一个Home页面跳到另外Details页面,并且携带了参数怎么在Details页面获取,就是这么简单粗暴.2 测试DemoApp.js文件如下...
1 问题在一个文件构建一个对象,然后在另外一个文件里面new这个对象,通过构造方法传递参数,然后再获取这个参数2 测试代码Student.js文件如下'use strict';import React from 'react'import {NativeModules, NativeEventEmitter, DeviceEventEmitter,Ale...
1 简单部分代码export default class App extends Component&amp;lt;Props&amp;gt; { render() { return ( &amp;lt;View {styles.container}&amp;gt; &amp;lt;View {styles.welcome}&amp;gt; &amp;l...
1 怎么实现发送和接收事件理论上封装了Android原生广播的代码,需要注册和反注册,这里用DeviceEventEmitter实现//增加监听DeviceEventEmitter.addListener//取消监听//this.emitter.remove();这里可也可以通过安卓原生向页面js发送消息,可以参考我的这篇博客React Native之Android原生通过Dev...
1、Component介绍一般Component需要被其它类进行继承,Component和Android一样,也有生命周期英文图片如下2 具体说明1)、挂载阶段constructor()//构造函数,声明之前先调用super(props)componentWillMount()//因为它发生在render()方法前,因此在该方法内同步设置状态...
1 触摸事件普通点击我们可以使用onPress方法,我们可以使用Touchable 系列控件设计我们的按钮TouchableHighlight 背景会在用户手指按下时变暗TouchableNativeFeedback用户手指按下时形成类似墨水涟漪的视觉效果TouchableOpacity指按下时降低按钮的透明度,而不会改变背景的颜色TouchableWithoutFeedbac...
1 问题部分代码如下class HomeScreen extends React.Component { render() { return ( &amp;lt;View {{ flex: 1, alignItems: 'center', justifyContent: 'center' }}&amp;gt; &amp;lt;Text&amp;gt;Home Scre...
1 Props(属性)和State(状态)和简单样式简单使用App.js代码如下/** * Sample React Native App * https://github.com/facebook/react-native * * @format * @flow */import React, {Component} from 'react';import {Pla...