【学习笔记】Flutter重要知识点

学习资料

4月28日-5月11日
按照这个视频边学习边敲代码
视频学习
争取两个星期把flutter和dart搞定!!!!

5月12日半夜更新学习日志
基本内容学的超不多了,感觉声明式编程真的好爱~~Android原生好久没搞了。接下来练几个Flutter项目!边学边找工作,相信自己,虽然二战考研失败了,但日子总是要过得…
加油!希望能在六月份之前在杭州找到工作!!

案例代码

点击跳转dart语法学习代码
点击跳转github案例代码
有新的代码我会push上去的。案例代码自个人跟着敲得,基本一些用法及笔记都标在注释里边了,这个学习视频其实版本是2020年的,有些组件废弃了,所以我也稍微修改了一下

一些说明

UI开发工具包Flutter,多用于移动端,跨平台,开发速度快(框架)

1.Dart语法学习

dart语言有很多其他语言的特征,js,python,java…

1.1 第一行代码

main(List<String> args) {
    print("Hello World");
}

VSCode运行
在这里插入图片描述

1.2 变量声明

// 1.变量声明
    String name = "WYJ";

    // 2.类型推导(var、final、const)
    // 变量是有类型的
    var age = 20;
    age = 30;

    // 3.final、const都是定义常量
    final height = 1.99;
    // height = 2.00;
    const address  ="浙江省";
    // address = "杭州市";

    //final与const之间的区别-final可以通过计算赋值,const必须赋值
    // const date1 = DateTime.now();写法错误
    final date1 = DateTime.now();

1.3 创建同一个实例和创建不同实例(final&const)

    //p1和p2不是同一个对象
    final p1 = Person("why");
    final p2 = Person("why");
    print(identical(p1, p2));

    //p1和p2是同一个对象
    const p3 = const Person("why");
    const p4 = const Person("why");
    const p5 = const Person("wangMing");
    print(identical(p3, p4));
    print(identical(p5, p4));
class Person {
  final String name;
  const Person(this.name);
}

运行截图
【学习笔记】Flutter重要知识点_第1张图片

1.4 bool类型

void main(List<String> args) {
  // var flag = "abc"; 没有非空即真
  var flag = true;
  if(flag){
    print("执行代码");
  }
}

dart中没有非空即真,bool类型需要设为true或false

1.5 字符串定义及使用

void main(List<String> args) {
  var str1 = 'abc';
  var str2 = "abc";
  var str3 = """
  abc
  def
  """;

  var name = "why";
  var age = 19;
  var height = 1.99;
  var message1 = "my name is ${name}, age is ${age}, height is ${height}";
  var message2 = "name is ${name}, type is ${name.runtimeType}";
  print(message1);
  print(message2);
}

【学习笔记】Flutter重要知识点_第2张图片
说明:类似于es6里的变量代换,利用${}来操作。

1.6 集合类型

void main(List<String> args) {
  // 1.列表List
  var names = ["abc", "cba", "nba"];
  names.add("value");
  
  // 2.集合Set
  var movies = {"aaa", "bbb", "ccc"};
  names = Set<String>.from(names).toList();
  print(names);

  // 3.映射Map
  var info = {
    "name":"key",
    "age":18
  };
}

1.7 函数简单使用

void main(List<String> args) {
  print(sum(1, 2));
}

int sum(int num1, int num2){
  return num1 + num2;
}

1.8 函数进阶(命名可选参数、位置可选参数)

void main(List<String> args) {
  sayHello1("why");
  sayHello2("why",18,178.1);
  sayHello3("why",age: 18, height: 178.1);
}
void sayHello1(String name){
  print(name);
}
//dart中没有函数的重载
//可选参数:位置可选参数-命名可选参数
//***位置可选参数***
//实参和形参进行匹配时,是根据位置进行匹配的
void sayHello2(String name, [int age = 0, double height = 0]) {
  print("my name is" + name + "; age is ${age}; height is ${height};");
}
//***命名可选参数***
void sayHello3(String name, {int age = 0, double height = 0}) {
  print("my name is" + name + "; age is ${age}; height is ${height};");
}

1.9 函数是第一公民

void main(List<String> args) {
  test(bar);
  test(() {
    print("匿名函数被调用");
    return 10;
  });
  //箭头函数:条件是只能有一行代码
  test(() => print("箭头函数被调用"));
}
//函数可以作为另一个函数的参数
void test(Function foo){
  foo();
}
void bar(){
  print("bar函数被调用");
}

这里用了箭头函数和匿名函数,箭头函数就用于只有一行代码的函数。

1.10 带参数的函数传入

如何在函数里面带参数呢,先简单写一段程序

void main(List<String> args) {
  test((num1, num2) {
    return num1 * num2;
  });
}
void test(int foo(int num1, int num2)) {
  foo(20,30);
}

确实可以实现传参,但是阅读起来不容易理解,所以改进一下。

typedef Calculate = int Function(int num1, int num2);
void test(Calculate calculate) {
  calculate(20, 30);
}

Function这阅读起来很不清楚,可以传参,也可以不传参,所以阅读性差;使用typedef定义一个函数,这样阅读起来简单明了

1.11 函数作为返回值

void main(List<String> args) {
  var demo1 = demo();
  print(demo1(20, 30));
}
typedef Calculate = int Function(int num1, int num2);
Calculate demo() {
  return ((num1, num2) {
    return num1 * num2;
  });
}

1.12 一般的运算符

问号使用

void main(List<String> args) {
  // ??= 有值则不赋值,没有值则赋值
  var name1 = "why";
  name1 ??= "lilei";
  print(name1);

  var name2 = null;
  name2 ??= "lilei";
  print(name2);

  //前面的数据为null,那么就使用后面的数据
  var name = null;
  var temp = name ?? "lilei";
  print(temp);
}

【学习笔记】Flutter重要知识点_第3张图片

1.13 级联运算符

main(List<String> args) {
  var p = person()
            ..name = "why"
            ..eat()
            ..run();
  print(p.name);
}
class person {
  String name = "";

  void run() {
    print("running...");
  }

  void eat() {
    print("eating...");
  }
}

【学习笔记】Flutter重要知识点_第4张图片

1.14 for循环

void main(List<String> args) {
  // 1.基础for循环
  for(var i = 0; i < 10; i++) {
    print(i);
  }

  // 2.遍历数组
  var names = ["why", "cha", "cba"];
  for(var i = 0; i < names.length; i++) {
    print(names[i]);
  }

  for(var name in names) {
    print(name);
  }
}

【学习笔记】Flutter重要知识点_第5张图片

1.15 类的定义

//dart支持函数式编程,但是大部分是面向对象,即类
void main(List<String> args) {
  var p = Person("why", 18);
}
class Person {
  String name;
  int age;

  原本写法
  // Person(String name, int age) {
  //   this.name = name;
  //   this.age = age;
  // }

  //简便写法
  Person(this.name, this.age);
}

1.16 构造函数

dynamic

  // Object调用方法时,编译时会出错
  // dynamic编译不会报错,但是运行时会报错

  // Object obj = "why";
  // print(obj.substring(1));

  dynamic obj = "why";
  // dynamic obj = 123;
  print(obj.substring(1));

命名构造函数

void main(List<String> args) {
  // Object调用方法时,编译时会出错
  // dynamic编译不会报错,但是运行时会报错

  // Object obj = "why";
  // print(obj.substring(1));

  dynamic obj = "why";
  // dynamic obj = 123;
  print(obj.substring(1));

  var p = Person.withNameAgeHeight("why", 18, 178.1);

  var p1 = Person.fromMap({
    "name": "lilei",
    "age": 18,
    "height": 178.1 
  });
  print(p1);
}
class Person {
  String name = "";
  int age = 0;
  double height = 0.0;

  Person(this.name,this.age);

  //命名构造函数
  //这里的withNameAgeHeight和fromMap都是自定义的
  Person.withNameAgeHeight(this.name, this.age, this.height);
  Person.fromMap(Map<String, dynamic> map) {
    this.name = map["name"];
    this.age = map["age"];
    this.height = map["height"];
  }

  @override
  String toString() {
    return "$name $age $height";
  }
}

【学习笔记】Flutter重要知识点_第6张图片

1.17 类的初始化列表

void main(List<String> args) {
  var p1 = Person("why");
  print(p1.age);
  var p2 = Person("why", age: 18);
  print(p2.age);
}
class Person {
  final String name;
  final int age;

  // 初始化age,初始化列表
  // Person(this.name): age = 10;
  // Person(this.name, {this.age = 10});
  Person(this.name, {age}): this.age = age ?? 10;
}

【学习笔记】Flutter重要知识点_第7张图片
p1未传入参数,那么赋值为10,当age为null时,赋值为10,;否则如p2,则赋值为传入的值18.

1.18 重定向构造函数

void main(List<String> args) {
  Person p = Person("WYJ");
  print("My name is ${p.name}, age is ${p.age}");
}

// 这里赋初始值是通过调用_internal函数的方式
// age 数值并未传入,但是初始化为0
class Person {
  String name;
  int age;
  Person(String name) :this._internal(name, 0);
  Person._internal(this.name,this.age);
}

【学习笔记】Flutter重要知识点_第8张图片

1.19 常量构造函数

void main(List<String> args) {
  //这里传入相同的名称时,指向的是同一个实例
  const p1 = Person("why");
  const p2 = Person("why");
  print(identical(p1, p2));

  // const p1 = Person("why1");
  // const p2 = Person("why2");
  // print(identical(p1, p2));
}

class Person {
  final String name;
  final int age;

  //常量构造函数
  const Person(this.name): this.age = 0;

  //dart不支持函数的重改
  // const Person(this.name, this.age);
}

1.20 工厂构造函数

void main(List<String> args) {
  final p1 = Person.withName("why");
  final p2 = Person.withName("why");
  print(identical(p1, p2));

  // final p1 = Person.withColor("yellow");
  // final p2 = Person.withColor("yellow");
  // print(identical(p1, p2));

  // final p1 = Person.withColor("yellow1");
  // final p2 = Person.withColor("yellow2");
  // print(identical(p1, p2));
}

//工厂构造函数最大的特点是可以手动的返回一个对象
//普通构造函数会自动返回创建出来的对象,不能手动的返回
class Person {
  String name;
  String color;

  /* 缓存,当传入的姓名是一样的时候,
   就返回缓存中的已有实例,否则创建新的实例*/
  static final Map<String, dynamic> _nameCache = <String, Person>{};
  static final Map<String, dynamic> _colorCache = <String, Person>{};

  //返回类型为factory,意味着必须返回一个实例。
  //自定义withName函数
  factory Person.withName(String name) {
    //判断map中有没有该名字
    if(_nameCache.containsKey(name)) {
      //有名字则返回已有的实例
      return _nameCache[name];
    } else {
      //否则创建新实例,同时color设置为"default"
      final p = Person(name, "default");
      _nameCache[name] = p;
      return p;
    }
  }

  //  类似有下面函数
  factory Person.withColor(String color) {
    if(_colorCache.containsKey(color)) {
      return _colorCache[color];
    } else {
      final p = Person("default", color);
      _colorCache[color] = p;
      return p;
    }
  }

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

【学习笔记】Flutter重要知识点_第9张图片

1.21 getter和setter

void main(List<String> args) {
  final p = Person();
  //直接访问属性
  p.name = "why";
  print(p.name);

  //通过getter和setter访问
  p.setName = "lilei";
  print(p.getName);
}

class Person {
  String name = "";
  //setter
  set setName(String name) {
    this.name = name;
  }
  //getter
  String get getName {
    return name;
  }
}

【学习笔记】Flutter重要知识点_第10张图片

1.22 类的继承

void main(List<String> args) {
  final p = Person("name", 10);
  print(p.name);
  print(p.age);
}

class Animal {
  int age;
  Animal(this.age);
}
class Person extends Animal {
  String name;

  //super(age)相当于调用Animal(this.age);
  Person(this.name, int age): super(age);
}

【学习笔记】Flutter重要知识点_第11张图片

1.23 抽象类的使用

void main(List<String> args) {
  final map = Map();
  print(map.runtimeType);
  // final s = Shape();
}

//抽象类不能调用原本的方法来实例化
abstract class Shape {
  int getArea();
  String getInfo() {
    return "形状";
  }

  //通过工厂实例化
  // factory Shape() {
  //   return Rectangle();
  // }
}

//继承自抽象类后,抽象类必须实现抽象类的抽象方法
// class Rectangle extends Shape {
//   @override
//   int getArea() {
//     return 100;
//   }
// }

1.24 隐式接口

void main(List<String> args) {
  
}

//Dart中没有关键字定义接口,默认所有的
//当将一个类当作接口使用时,那么实现这个接口的类,必须实现这个接口中的所有方法
class Runner {
  void running() {
    print("running");
  }
}
class Flyer {
  void flying() {

  }
}
class Animal {
  void eating() {
    print("动物吃东西");
  }
}
class Superman extends Animal implements Flyer, Runner {
  @override
  void running() {
    // TODO: implement running
  }
  @override
  void flying() {
    // TODO: implement flying
  }
  @override
  void eating() {
    // TODO: implement eating
    super.eating();
  }
}

1.25 mixin混入的使用

void main(List<String> args) {
  final sm = SuperMan();
  sm.running();
  sm.flying();
}
class Animal {
  void eating() {
    print("动物吃东西");
  }
  void running() {
    print("animal running");
  }
}
mixin Flyer {
  void flying() {
    print("flying");
  }
}
mixin runner {
  void running() {
    print("runner running");
  }
}

//调用顺序,先看自己有没有定义的方法,再去调用混入,没有再看继承的
class SuperMan extends Animal with runner, Flyer{
  @override
  void eating() {
    // TODO: implement eating
    super.eating();
  }
  // //加入混入就不需要写running
  // @override
  // void running() {
  //   // TODO: implement running
  //   super.running();
  // }

  //重写running,会最先调用这里的running
  // void running() {
  //   print("superMan running");
  // }
}

在这里插入图片描述

1.26 静态方法(类方法)和静态属性(类属性)

void main(List<String> args) {
  Person.courseTime = "8:00";
  Person.gotoCourse();
}
class Person {
  //成员属性
  String name = "";

  //静态属性(类属性)
  static String courseTime = "";

  //对象方法
  void eating() {
    print("eating");
  }

  //静态方法(类方法)
  static void gotoCourse() {
    print("去上课");
  }
}

【学习笔记】Flutter重要知识点_第12张图片

1.27 枚举

// 枚举 enum ,枚举作用是安全,保证传入的数据安全,不会有其他规定以外的数据传入
void main(List<String> args) {
  final color = Colors.red;
  switch(color) {
    case Colors.red:
    print("red");
    break;
    case Colors.blue:
    print("blue");
    break;
  }
  print(Colors.values);
  print(Colors.red.index);
}
enum Colors {
  red,
  blue
}

【学习笔记】Flutter重要知识点_第13张图片

1.28 库的使用

import 'dart:io';
import 'dart:async';
import 'dart:io';
import 'dart:math';
//系统库格式: import 'dart:库的名称'
import 'util.dart' as mUtils;
// import 'util.dart' show sum, mul;
// import 'util.dart' hide sum, mul;
void main(List<String> args) {
  //math
  final num1 = 20;
  final num2 = 30;
  print(min(num1, num2));

  print(mUtils.sum(num1, num2));
  print(mUtils.mul(num1, num2));

  //下划线是区分方法是私有还是公有的
  // print(mUtils._privateSum)

}
int sum(int num1, int num2) {
  return num1 + num2;
}

【学习笔记】Flutter重要知识点_第14张图片
util.dart

export 'dateUtil.dart';
export 'mathUtils.dart';

int sum(int num1, int num2) {
  return num1 + num2;
} 
int mul(int num1, int num2) {
  return num1 * num2;
}
int _privateSum(int num1, int num2) {
  return num1 * num2;
}

1.29 第三方库

// https://pub.dev/packages/http/install
import 'package:http/http.dart' as http;

void main(List<String> args) async{
  var url = Uri.parse('https://example.com/whatsit/create');
  var response = await http.post(url, body: {'name': 'doodle', 'color': 'blue'});
  print('Response status: ${response.statusCode}');
  print('Response body: ${response.body}');

  print(await http.read(Uri.parse('https://example.com/foobar.txt')));
}

pubspec.yaml

name: WYJ
description: a dart library
environment:
  sdk: '>=2.10.0 <3.0.0'
dependencies: 
  http: ^0.13.4

至此dart语法结束(5月6日补充新知识)

1.30 future简单使用

import 'dart:io';

void main(List<String> args) {
  print("main start");
  //发送一个网络请求
  var future = getNetworkData();
  print(future);

  //需要在Future函数有结果,才执行下面的回调函数
  future.then((String value) {
    print(value);
  }).catchError((onError){
    print(onError);
  }).whenComplete(() => print("代码执行完成"));
    print("main end");
}
//模拟一个网络请求
Future<String> getNetworkData() {
  //将耗时的操作包裹在future的回调函数中
  //只要有回调函数,那么就执行Future对应的then的回调
  //如果没有结果返回,就抛出一个异常
  return Future<String>(() {
      sleep(Duration(seconds: 3));
      return "Hello World";
      throw Exception("错误信息");
    }
  );
}

【学习笔记】Flutter重要知识点_第15张图片

1.31 future链式调用

import 'dart:io';

void main(List<String> args) {
  print("Main Start");

  Future(() {
    sleep(Duration(seconds: 3));
    return "第一次结果";
  }).then((value) {
    print(value);
    //第二次请求
    sleep(Duration(seconds: 2));
    return "第二次结果";
  }).then((value) {
    print(value);
    //第三次请求
    sleep(Duration(seconds: 1));
    return "第三次结果";
  }).then((value) => print(value));

  print("Main end");
}

【学习笔记】Flutter重要知识点_第16张图片

1.32 future其他API

void main(List<String> args) {
  Future(() {
    return "Hello World";
  },).then((value) => print(value));

  Future.value("hahaha").then((value) => print(value));

  Future.error("error").catchError((Error){
    print(Error);
  });

  Future<String>.delayed(Duration(seconds: 3)).then((value) {
    return "Hello";
  }).then((value) => print(value));
}

【学习笔记】Flutter重要知识点_第17张图片

1.33 await async

import 'dart:io';
void main(List<String> args) {
  print("main start");
  getData();
  print("main end");
}
void getData() async{
  //调用三次网络请求
  // getNetworkData("arguement").then((value) {
  //   print(value);
  //   return getNetworkData(value);
  // }).then((value) {
  //   print(value);
  //   return getNetworkData(value);
  // }).then((value) {
  //   print(value);
  // });
  var res1 = await getNetworkData("arguement");
  print(res1);
  var res2 = await getNetworkData(res1);
  print(res2);
  var res3 = await getNetworkData(res2);
  print(res3);
}
Future getNetworkData(String arg) {
  return Future((() {
    sleep(Duration(seconds: 3));
    return "Hello World" + arg;
  }));
}

1.34 isolate

import 'dart:isolate';

void main(List<String> args) async{
  print("main start");

  // 1.创建Isolate
  Isolate.spawn((int message) { 
    var total = 0;
    for(var i=0;i<message;i++){
      total+=i;
    }
    print(total);
  }, 100);

  //iolate双向通信
  // 1.创建管道
  ReceivePort receivePort = ReceivePort();
  // 2.创建Isolate
  Isolate isolate = await Isolate.spawn<SendPort>(foo, receivePort.sendPort);
  // 3.监听管道
  receivePort.listen((message) {
    print(message);
    receivePort.close();
    isolate.kill();
  },);

  print("main end");
}

void foo(SendPort sendPort) {
  return sendPort.send("Hello World");
}

2. Flutter学习

2.1 创建一个新的Flutter项目(命令行创建)

Flutter create learn_flutter

打开main.dart,删除里面的内容,重写代码
每一个小组件是一个Widget,许多的Widget又构成一个个Widget。一个完整的App是一颗Widget树。
StatelessWidget是无状态Widget。
每一个Widget里面有一个必须实现的方法build

import 'package:flutter/material.dart';

//只有一句代码就可以使用箭头函数
main() => runApp(MyApp());

//Widget分为有状态和无状态
//有状态是运行过程中有一些状态需要改变
//无状态则是内容无需改变
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(debugShowCheckedModeBanner: false, home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text("标题"),
        ),
        body: HYContentBody());
  }
}

class HYContentBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Center(
        child: Text(
      "Hello World",
      style: TextStyle(fontSize: 30, color: Colors.orange),
    ));
  }
}

【学习笔记】Flutter重要知识点_第18张图片
这种写法使得多层嵌套的代码变得可读性强

2.2 案例一(chechbox)

需要构造一个这样的功能的界面
【学习笔记】Flutter重要知识点_第19张图片

import 'package:flutter/material.dart';

//只有一句代码就可以使用箭头函数
main() => runApp(MyApp());

//Widget分为有状态和无状态
//有状态是运行过程中有一些状态需要改变
//无状态则是内容无需改变
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(debugShowCheckedModeBanner: false, home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text("标题"),
        ),
        body: HYContentBody());
  }
}
//row是可以包含多个组件
class HYContentBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Center(
      child: Row(
        //mainAxisAlignment居中
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Checkbox(
            value: true,
            onChanged: (value) => print(value),
          ),
          Text("同意协议", style: TextStyle(fontSize: 20),)
        ],
      ),
    );
  }
}

但是点击checkbox的按钮,没什么反应,这是应为使用了statelessWiidget,更改代码

import 'package:flutter/material.dart';

//只有一句代码就可以使用箭头函数
main() => runApp(MyApp());

//Widget分为有状态和无状态
//有状态是运行过程中有一些状态需要改变
//无状态则是内容无需改变
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(debugShowCheckedModeBanner: false, home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text("标题"),
        ),
        body: HYContentBody());
  }
}
class HYContentBody extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return HYContentBodyState();
  }
}
//stateful不能定义状态 -》 创建一个单独的类,这个类负责维护状态
class HYContentBodyState extends State<HYContentBody> {
  var flag = true;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        //mainAxisAlignment居中
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Checkbox(
            value: flag,
            onChanged: (value) {
              //这里的setSate是通知界面更新
              setState(() {
                flag = value!;
              });
            },
          ),
          Text("同意协议", style: TextStyle(fontSize: 20),)
        ],
      ),
    );
  }
}

【学习笔记】Flutter重要知识点_第20张图片
这样点击就可以改变选中和不选中了

2.3 案例二(Column和flutter项目安全区域)

【学习笔记】Flutter重要知识点_第21张图片
构造上面界面,对应代码如下

import 'package:flutter/material.dart';
import 'package:flutter_learn/02_checkbox.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}
class HYHomePage extends StatelessWidget {
  const HYHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("商品列表"),
      ),
      body: HYHomeContent(),
    );
  }
}
class HYHomeContent extends StatelessWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //Column能使里面的Widget按列的形式排列
    return Column(
      children: [
        HYHomeProjectItem("Apple", "MacBook", "https://wx2.sinaimg.cn/mw1024/005yGqLdly1h1uknlr8ojj30wi0f0t9k.jpg"),
        HYHomeProjectItem("banana", "WindowsBook", "https://wx3.sinaimg.cn/mw1024/005yGqLdly1h1uknm0xr4j30wi0f0wey.jpg"),
        HYHomeProjectItem("orange", "LinuxBook", "https://wx2.sinaimg.cn/mw1024/6c5b0aa9gy1h1uyicv0zzj20ah0cs74n.jpg"),
      ],
    );
  }
}
class HYHomeProjectItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeProjectItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(title),
        Text(desc),
        Image.network(imageURL)
      ],
    );
  }
}

Column的作用是将里面的Widget按列的方式垂直排列,那么我们看到这种效果,在每一个HYHomeProjectItem
【学习笔记】Flutter重要知识点_第22张图片
也需要Column对内部的Text,Text,Imag进行排列。

我们注意到下面有黄条
【学习笔记】Flutter重要知识点_第23张图片
这个表示显示的内容超过了屏幕显示区域。

2.4 案例三(计数器)

import 'package:flutter/material.dart';
import 'package:flutter_learn/02_checkbox.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}
class HYHomePage extends StatelessWidget {
  const HYHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("商品列表"),
      ),
      body: HYHomeContent(),
    );
  }
}

//Widget是暴露给别人使用的,state是私有的
class HYHomeContent extends StatefulWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

//当状态改变时,并不希望重新创建新的state
class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _getButton(),
          Text("当前计数: $_counter", style: TextStyle(fontSize: 25),)
        ],
      ),
    );
  }

  Widget _getButton() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ElevatedButton(
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
          child: Text("+", style: TextStyle(fontSize: 20, color: Colors.white),),
          style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.green)
          ),
        ),
        ElevatedButton(
          onPressed: () {
            setState(() {
              _counter--;
            });
          },
          child: Text("-", style: TextStyle(fontSize: 20, color: Colors.white),),
          style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.red)
          ),
        )
      ],
    );
  }
}

【学习笔记】Flutter重要知识点_第24张图片

2.5 从Widget传递信息到State

【学习笔记】Flutter重要知识点_第25张图片
【学习笔记】Flutter重要知识点_第26张图片
【学习笔记】Flutter重要知识点_第27张图片

2.6 生命周期

生命周期说的简单些是回调,钩子。生命周期的函数作用是
1、初始化一些东西
2、监听组件的事件
3、管理内存(手动销毁)

在flutter中只需要监听Widget的生命周期。
statelessWidget调用build方法和构造函数

class HYHomePage extends StatelessWidget {
  final String str;

  HYHomePage(this.str) {
    print("构造函数调用");
  }

  @override
  Widget build(BuildContext context) {
    print("调用build方法");
    return Text("aaa");
  }
}

【学习笔记】Flutter重要知识点_第28张图片

statefulWidget生命周期

import 'package:flutter/material.dart';
import 'package:flutter_learn/02_checkbox.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}
class HYHomePage extends StatelessWidget {

  HYHomePage() {
    print("调用HYHomePage的构造函数");
  }

  @override
  Widget build(BuildContext context) {
    print("调用HYHomePage的build方法");
    return Scaffold(
      appBar: AppBar(
        title: Text("生命周期"),
      ),
      body: HYHomeContent(),
    );
  }
}
class HYHomeContent extends StatefulWidget {
  HYHomeContent() {
    print("1、调用HYHomeContent的构造函数");
  }

  @override
  State<HYHomeContent> createState() {
    print("2、调用_HYHomeContent的createState方法");
    return _HYHomeContentState();
  }
}

class _HYHomeContentState extends State<HYHomeContent> {
  int _count = 0;

  _HYHomeContentState() {
    print("3、调用_HYHomeContentState的构造函数");
  }
  @override
  void initState() {
    //这里是必须调用super
    //原因:父类做初始化、mustcallSuper注解
    print("4、调用_HYHomeContentState的initState方法");
    super.initState();

  }
  @override
  Widget build(BuildContext context) {
    print("5、调用_HYHomeContentState的build方法");
    return Column(
      children: [
        ElevatedButton(
            onPressed: () {
              setState(() {
                _count++;
              });
            },
            child: Icon(Icons.add)
        ),
        Text("数字:$_count")
      ],
    );
  }
  @override
  void didChangeDependencies() {
    print("调用_HYHomeContentState的didChangeDependencies方法");
    super.didChangeDependencies();
  }
  @override
  void didUpdateWidget(covariant HYHomeContent oldWidget) {
    print("调用_HYHomeContentState的didUpdateWidget方法");
    super.didUpdateWidget(oldWidget);
  }
  @override
  void dispose() {
    print("6、调用_HYHomeContentState的dispose方法");
    super.dispose();
  }
}

【学习笔记】Flutter重要知识点_第29张图片
按照图上的顺序1-5,以及dispose。当点击按钮时会调用build方法。

2.7 富文本使用

class HYHomeContent extends StatefulWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  Widget build(BuildContext context) {
    return Text.rich(
      TextSpan(
        children: [
          TextSpan(text: "Hello World",style: TextStyle(color: Colors.red, fontSize: 20)),
          WidgetSpan(child: Icon(Icons.favorite, color: Colors.red,)),
          TextSpan(text: "Hello World",style: TextStyle(color: Colors.red, fontSize: 20)),
        ]
      )
    );
  }
}

【学习笔记】Flutter重要知识点_第30张图片

2.8 button widget

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}
class HYHomePage extends StatelessWidget {
  const HYHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("基础的Widget"),
      ),
      body: HYHomeContent(),
      floatingActionButton: FloatingActionButton(
        onPressed: () => print("FloatingActionButton Click"),
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}
class HYHomeContent extends StatefulWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  Widget build(BuildContext context) {
    return Column(
      //Column主轴是垂直,Row主轴是水平,Column在交叉轴上会居中显示内容
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        ElevatedButton(
          onPressed: () => print("ElevatedButton Click"),
          child: Text("ElevatedButton"),
          style: ButtonStyle(
            backgroundColor: MaterialStateProperty.all(Colors.red),
            foregroundColor: MaterialStateProperty.all(Colors.white),
          ),
        ),
        TextButton(
          onPressed: () => print("TextButton Click"),
          child: Text("TextButton"),
          style: ButtonStyle(
            backgroundColor: MaterialStateProperty.all(Colors.lightBlue),
            foregroundColor: MaterialStateProperty.all(Colors.white),
          ),
        ),
        OutlinedButton(
          onPressed: () => print("OutlineButton"),
          child: Text("OutlinedButton"),
          style: ButtonStyle(
            backgroundColor: MaterialStateProperty.all(Colors.orange),
            foregroundColor: MaterialStateProperty.all(Colors.white),
          ),
        ),
        TextButton(
          onPressed: () => print("click"),
          child: Row(
            //row默认会在主轴延伸至最大,这里设置为最小
            mainAxisSize: MainAxisSize.min,
            children: [
              Icon(Icons.favorite, color: Colors.redAccent),
              Text("喜欢作者")
            ],
          ),
          style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.lightBlue),
              foregroundColor: MaterialStateProperty.all(Colors.white),
              shape: MaterialStateProperty.all(
                  ContinuousRectangleBorder(
                      side: BorderSide.none,
                      borderRadius: BorderRadius.all(Radius.circular(20))
                  )
              )
          ),
        )
      ],
    );
  }
}

【学习笔记】Flutter重要知识点_第31张图片

2.9 image widget


main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}

class HYHomePage extends StatelessWidget {
  const HYHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("基础的Widget"),
      ),
      body: ImageDemo02(),
    );
  }
}

class ImageDemo01 extends StatefulWidget {
  @override
  State<ImageDemo01> createState() => _ImageDemo01State();
}

class _ImageDemo01State extends State<ImageDemo01> {
  final _imageURL = "https://img.zcool.cn/community/01ad5d57d418eb0000018c1b65ed20.jpg@1280w_1l_2o_100sh.jpg";

  @override
  Widget build(BuildContext context) {
    return Image(
      image: NetworkImage(_imageURL),
      width: 200,
      height: 200,
      //宽度为200,高度自适应
      fit: BoxFit.contain,
      //矩形框最左上角为(-1,-1),最右下角为(1,1),中间为(0.0)
      alignment: Alignment(0,0),
      color: Colors.green,
      colorBlendMode: BlendMode.colorDodge,
      repeat: ImageRepeat.repeatY,
    );
  }
}

class ImageDemo02 extends StatefulWidget {
  @override
  State<ImageDemo02> createState() => _ImageDemo02State();
}

class _ImageDemo02State extends State<ImageDemo02> {
  @override
  Widget build(BuildContext context) {
    // return Image(
    //   // 1、创建文件夹存储图片
    //   // 2、在pubspec.yaml进行配置
    //   // 3、使用图片
    //     image: AssetImage("assets/images/test.jpg")
    // );
    return Image.asset("assets/images/test.jpg");
  }
}

【学习笔记】Flutter重要知识点_第32张图片
【学习笔记】Flutter重要知识点_第33张图片【学习笔记】Flutter重要知识点_第34张图片
【学习笔记】Flutter重要知识点_第35张图片

2.10 图片扩展案例&按钮扩展案例

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}

class HYHomePage extends StatelessWidget {
  const HYHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("基础的Widget"),
      ),
      body: ButtonExtension(),
    );
  }
}

class ButtonExtension extends StatefulWidget {
  const ButtonExtension({Key? key}) : super(key: key);

  @override
  State<ButtonExtension> createState() => _ButtonExtensionState();
}

class _ButtonExtensionState extends State<ButtonExtension> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ButtonTheme(
          minWidth: 30,
          height: 10,
          child: FlatButton(
            padding: EdgeInsets.all(0),
            color: Colors.red,
            materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
            onPressed: () {},
            child: Text("Flate Button"),
            textColor: Colors.white,
          ),
        )
      ],
    );
  }
}

class ImageExtensionDemo extends StatefulWidget {
  @override
  State<ImageExtensionDemo> createState() => _ImageExtensionDemoState();
}

class _ImageExtensionDemoState extends State<ImageExtensionDemo> {
  final String _imageURL =
      "https://img.zcool.cn/community/01ad5d57d418eb0000018c1b65ed20.jpg@1280w_1l_2o_100sh.jpg";

  @override
  Widget build(BuildContext context) {
    return FadeInImage(
        fadeOutDuration: Duration(milliseconds: 1000),
        fadeInDuration: Duration(milliseconds: 1000),
        placeholder: AssetImage("assets/images/test.jpg"),
        image: NetworkImage(_imageURL));
  }
}

【学习笔记】Flutter重要知识点_第36张图片

2.11 图标使用

class IconExtension extends StatefulWidget {
  const IconExtension({Key? key}) : super(key: key);

  @override
  State<IconExtension> createState() => _IconExtensionState();
}

class _IconExtensionState extends State<IconExtension> {
  @override
  Widget build(BuildContext context) {
    // 1、矢量图放大不失真
    // 字体图标可以设置颜色
    // 图标很多时,占据空间小
    // return Icon(Icons.pets, size: 300, color: Colors.orange,);
    // return Icon(IconData(0xe91d, fontFamily: 'MaterialIcons'), size: 300, color: Colors.orange,);
    //传入unicode编码
    return Text("\ue91d", style: TextStyle(fontSize: 100, color: Colors.orange, fontFamily: 'MaterialIcons'));
  }
}

【学习笔记】Flutter重要知识点_第37张图片

2.12 登录功能案例

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
      theme: ThemeData(
        // Colors.red
        // Colors.red[100]
        // Color(0xffffffff)
        // Color.fromRGBO(111, 100, 100, 50)
        primaryColor: ,
        colorScheme: const ColorScheme.light(
          //顶部栏栏颜色
          primary: Colors.red,
          //顶部栏字体颜色
          onPrimary: Colors.white,
          onBackground: Colors.white,

        )
      ),
    );
  }
}

class HYHomePage extends StatelessWidget {
  const HYHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("基础的Widget"),
      ),
      body: TextFieldDemo(),
    );
  }
}
class TextFieldDemo extends StatefulWidget {
  const TextFieldDemo({Key? key}) : super(key: key);

  @override
  State<TextFieldDemo> createState() => _TextFieldDemoState();
}

class _TextFieldDemoState extends State<TextFieldDemo> {
  final usernameTextEditController = TextEditingController();
  final passwordTextEditController = TextEditingController();

  @override
  Widget build(BuildContext context) {

    return Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: TextField(
                controller: usernameTextEditController,
                decoration: InputDecoration(
                  labelText: "user name",
                  icon: Icon(Icons.people),
                  hintText: "请输入用户名",
                  border: InputBorder.none,
                  fillColor: Colors.red[100],
                  filled: true
                ),
                onChanged: (value) => {
                  print(value)
                },
                onSubmitted: (value) => {
                  print(value)
                },
              ),
            ),
            SizedBox(height: 10,),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: TextField(
                controller: passwordTextEditController,
                decoration: InputDecoration(
                  labelText: "password",
                  icon: Icon(Icons.lock),
                  border: OutlineInputBorder()
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Container(
                height: 40,
                width: double.infinity,
                child: FlatButton(
                  child: Text("登 录", style: TextStyle(fontSize: 20, color: Colors.white),),
                  onPressed: () {
                    //获取用户名和密码
                    final String username = usernameTextEditController.text;
                    final String password = passwordTextEditController.text;
                    print("账号:${username}; 密码:${password}");
                  },
                  color: Colors.blue,
                ),
              ),
            )
          ],
        ),
      );
  }
}

【学习笔记】Flutter重要知识点_第38张图片

2.13 单个子组件布局案例

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomeContent()
    );
  }
}
class HYHomeContent extends StatelessWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ContainerDemo(),
      appBar: AppBar(
        title: Text("布局"),
      ),
    );
  }
}

class ContainerDemo extends StatefulWidget {
  const ContainerDemo({Key? key}) : super(key: key);

  @override
  State<ContainerDemo> createState() => _ContainerDemoState();
}

class _ContainerDemoState extends State<ContainerDemo> {
  @override
  Widget build(BuildContext context) {
    return Container(
      //这里的颜色加上会与decoration里面的颜色冲突,选择其中一个
      // color: Colors.red,
     width: 200,
     height: 200,
      //在container里面加入Alignment,里面有子组件时,构成一个三层机构,子组件文本不会放大,在Align里面居中显示
      //若不加上Alignment会使Text扩大到Container设置的宽度高度一般大小,这样文本从左上角开始排列,也就不是居中了
      // alignment: Alignment(0,0),
     padding: EdgeInsets.all(20),
     margin: EdgeInsets.all(50),
     child: Text("data"),
     // child: Icon(Icons.pets, size: 50, color: Colors.blue,),
      decoration: BoxDecoration(
        color: Colors.red,
        border: Border.all(
          width: 5,
          color: Colors.black
        ),
        //圆形设置为100
        // borderRadius: BorderRadius.circular(100),
          borderRadius: BorderRadius.circular(10),
        boxShadow: [
          //Offset(x,y),x为正,往右,y为正,往下
          //spreadRadius延伸,在offset基础上延伸,blurRadius是模糊
          BoxShadow(color: Colors.orange,offset: Offset(10,10),spreadRadius: 5,blurRadius: 10),
          BoxShadow(color: Colors.green,offset: Offset(-10,-10),spreadRadius: 5,blurRadius: 10)
        ]
      ),
    );
  }
}



class PaddingDemo extends StatefulWidget {
  const PaddingDemo({Key? key}) : super(key: key);

  @override
  State<PaddingDemo> createState() => _PaddingDemoState();
}

class _PaddingDemoState extends State<PaddingDemo> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Padding(
          //EdgeInsets.symmetric(vertical: 5,horizontal: 0)
          padding: const EdgeInsets.only(
            bottom: 10
          ),
          child: Text("Hello WYJ", style: TextStyle(fontSize: 30, backgroundColor: Colors.red),),
        ),
        Text("Hello WYJ", style: TextStyle(fontSize: 30, backgroundColor: Colors.red),),
        Text("Hello WYJ", style: TextStyle(fontSize: 30, backgroundColor: Colors.red),)
      ],
    );
  }
}


class AlignDemo extends StatefulWidget {
  const AlignDemo({Key? key}) : super(key: key);

  @override
  State<AlignDemo> createState() => _AlignDemoState();
}

class _AlignDemoState extends State<AlignDemo> {
  @override
  Widget build(BuildContext context) {
    //Center就是Align
    return Container(
      width: 200,
      height: 200,
      color: Colors.amber,
      child: Align(
        // //高度和宽度的倍数
        // widthFactor: 5,
        // heightFactor: 5,
        //左上角为(-1,-1),右下角为(1,1),中心点为(0,0)
        alignment: Alignment(0, 0),
        child: Text("Hello"),
        // child: Icon(Icons.pets, size: 100,),
      ),
    );
  }
}

【学习笔记】Flutter重要知识点_第39张图片

2.14 flex

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomeContent()
    );
  }
}
class HYHomeContent extends StatelessWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FlexDemo(),
      appBar: AppBar(
        title: Text("布局"),
      ),
    );
  }
}

class FlexDemo extends StatefulWidget {
  const FlexDemo({Key? key}) : super(key: key);

  @override
  State<FlexDemo> createState() => _FlexDemoState();
}

class _FlexDemoState extends State<FlexDemo> {
  @override
  Widget build(BuildContext context) {
    //Row/Column:继承自Flex
    //Flex:CSS Flex布局
    //Axis.horizontal水平Row;Axis.vertical垂直colum
    return Container(
      height: 300,
      child: Row(
        /**
         * start是主轴开始、end是主轴结束开始、center是主轴中心开始,其他元素评分距离
         * MainAxisAlignment
         * -spacebetween是左右两边设置为0,其他元素之间平分间距
         * -spaceAround左右两边的间距是其他元素之间的间距的一半
         * -spaceEvenly所有间距均分距离
         * CrossAxisAlignment
         * -start从交叉轴起始位置对齐
         * -end从交叉轴结束为止对齐
         * -center中心对齐
         * -baseline基线对齐,按照文字的基线对齐,当内容有文本时,基线对齐才起作用
         * -stretch是现将Row尽可能的拉伸最大的空间,将所有的子Widget交叉轴的高度拉伸到最大
         */
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        textBaseline: TextBaseline.alphabetic,
        // textDirection: TextDirection.rtl,
        children: [
        Container(width: 80, height: 60,color: Colors.red, child: Text("Hello", style: TextStyle(fontSize: 10),)),
        Container(width: 90, height: 100,color: Colors.green, child: Text("Hello", style: TextStyle(fontSize: 30),)),
        Container(width: 50, height: 120,color: Colors.orange, child: Text("Hello", style: TextStyle(fontSize: 20),)),
        Container(width: 70, height: 110,color: Colors.blue, child: Text("Hello", style: TextStyle(fontSize: 40),)),
      ],),
    );
  }
}
class FlexDemo02 extends StatefulWidget {
  const FlexDemo02({Key? key}) : super(key: key);

  @override
  State<FlexDemo02> createState() => _FlexDemo02State();
}

class _FlexDemo02State extends State<FlexDemo02> {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      color: Colors.blue,
        onPressed: () => print("按钮点击"),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.pets),
          Text("button")
        ],
      ),
    );
  }
}


【学习笔记】Flutter重要知识点_第40张图片

expanded

class FlexDemo extends StatefulWidget {
  const FlexDemo({Key? key}) : super(key: key);

  @override
  State<FlexDemo> createState() => _FlexDemoState();
}

class _FlexDemoState extends State<FlexDemo> {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.center,
        textBaseline: TextBaseline.alphabetic,
        children: [
          /**
           * Flexible中的属性:
           * - flex
           * Expanded(更多)-》flexible(fit:Flexfit:tight)
           * 空间分配问题
           *
           */
          Expanded(
            flex: 1,
              child: Container(
                width: 50,
                height: 60,
                color: Colors.red,
              )
          ),
          Expanded(
            flex: 1,
            child: Container(
                width: 50,
                height: 100,
                color: Colors.green,
                ),
          ),
          Container(
              width: 50,
              height: 120,
              color: Colors.orange,
              ),
          Container(
              width: 70,
              height: 110,
              color: Colors.blue,
              ),
        ],
      ),
    );
  }
}

【学习笔记】Flutter重要知识点_第41张图片

2.15 stack(组件重叠)

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HYHomeContent());
  }
}

class HYHomeContent extends StatelessWidget {
  const HYHomeContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StackDemo02(),
      appBar: AppBar(
        title: Text("布局"),
      ),
    );
  }
}

class StackDemo01 extends StatefulWidget {
  const StackDemo01({Key? key}) : super(key: key);

  @override
  State<StackDemo01> createState() => _StackDemo01State();
}

class StackDemo02 extends StatefulWidget {
  const StackDemo02({Key? key}) : super(key: key);

  @override
  State<StackDemo02> createState() => _StackDemo02State();
}

class _StackDemo02State extends State<StackDemo02> {
  bool _isFavorite = false;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Image.asset(
          "assets/images/test.jpg",
        ),
        Positioned(
          left: 0,
          right: 0,
          bottom: 0,
          child: Container(
            width: double.infinity,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    "photo",
                    style: TextStyle(fontSize: 20, color: Colors.white),
                  ),
                  // GestureDetector(child: Icon(Icons.favorite, color: Colors.white,)),
                  IconButton(
                      onPressed: () {
                        setState(() {
                          this._isFavorite = !this._isFavorite;
                        });
                      },
                      icon: Icon(
                        Icons.favorite,
                        color: this._isFavorite == true ? Colors.red : Colors.white,
                      ))
                ],
              ),
            ),
            color: Color.fromARGB(150, 0, 0, 0),
          ),
        )
      ],
    );
  }
}

class _StackDemo01State extends State<StackDemo01> {
  @override
  Widget build(BuildContext context) {
    /**
     * Stack默认的大小是包裹内容的
     * - alignment从什么位置开始排布所有的子Widget
     * - fit:expand将子元素拉伸到尽可能大
     * - overflow:超出部分如何处理
     */
    return Stack(
      alignment: Alignment.center,
      // fit: StackFit.expand,
      // clipBehavior: Clip.none,
      children: [
        Image.asset(
          "assets/images/test.jpg",
          width: 300,
          fit: BoxFit.cover,
        ),
        Positioned(
          left: 0,
          bottom: -50,
          child: Container(
            width: 150,
            height: 150,
            color: Colors.red,
          ),
        ),
        Positioned(
          child: Text(
            "photo",
            style: TextStyle(fontSize: 20, color: Colors.green),
          ),
          //left:0表示距离左侧为0
          left: 0,
        )
      ],
    );
  }
}

【学习笔记】Flutter重要知识点_第42张图片

2.16 gridView

import 'dart:math';

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: HYHomeContent(),
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  Widget build(BuildContext context) {
    return GridViewDemo03();
  }
}

class GridViewDemo03 extends StatelessWidget {
  const GridViewDemo03({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8),
      child: GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            mainAxisSpacing: 8,
            crossAxisSpacing: 8
          ),
          itemBuilder: (BuildContext ctx, int index){
            return Container(
              color: Color.fromARGB(255, Random().nextInt(255),
                  Random().nextInt(255), Random().nextInt(255)),
            );
          }
      ),
    );
  }
}

class GridViewDemo02 extends StatelessWidget {
  const GridViewDemo02({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8),
      child: GridView(
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: 200,
          crossAxisSpacing: 8,
          mainAxisSpacing: 8,
          childAspectRatio: 0.8
        ),
        children: List.generate(100, (index) {
          return Container(
            color: Color.fromARGB(255, Random().nextInt(255),
                Random().nextInt(255), Random().nextInt(255)),
          );
        }),
      ),
    );
  }
}

class GridViewDemo01 extends StatelessWidget {
  const GridViewDemo01({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8),
      child: GridView(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
            childAspectRatio: 0.8,
            crossAxisSpacing: 8,
            mainAxisSpacing: 8),
        children: List.generate(100, (index) {
          return Container(
            color: Color.fromARGB(255, Random().nextInt(255),
                Random().nextInt(255), Random().nextInt(255)),
          );
        }),
      ),
    );
  }
}

2.17 scrollView

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // appBar: AppBar(
      //   title: Text("Custom ScrollView"),
      // ),
      body: HYHomeContent(),
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverAppBar(
          pinned: true,
          expandedHeight: 300,
          flexibleSpace: FlexibleSpaceBar(
            title: Text("Hello world",),
            background: Image.asset("assets/images/test.jpg", fit: BoxFit.cover,),
          ),
        ),
        SliverGrid(
            delegate: SliverChildBuilderDelegate(
                    (BuildContext ctx, int index) {
                  return Container(
                    color: Color.fromARGB(
                        255, Random().nextInt(256), Random().nextInt(256),
                        Random().nextInt(256)),
                  );
                },
              childCount: 10
            ),
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 8,
                mainAxisSpacing: 8,
                childAspectRatio: 1.5
            )
        ),
        SliverList(
            delegate: SliverChildBuilderDelegate(
                    (BuildContext ctx, int index) {
                  return ListTile(
                    leading: Icon(Icons.people),
                    title: Text("联系人$index"),
                  );
                },
                childCount: 20
            )
        )
      ],
    );
  }
}

class CustomScrollViewDemo01 extends StatelessWidget {
  const CustomScrollViewDemo01({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        //区别safeArea
        SliverSafeArea(
          sliver: SliverPadding(
            padding: EdgeInsets.all(8),
            sliver: SliverGrid(
                delegate:
                SliverChildBuilderDelegate((BuildContext ctx, int index) {
                  return Container(
                    color: Color.fromARGB(255, Random().nextInt(255),
                        Random().nextInt(255), Random().nextInt(255)),
                  );
                }, childCount: 10),
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    crossAxisSpacing: 8,
                    mainAxisSpacing: 8,
                    childAspectRatio: 1.5)),
          ),
        )
      ],
    );
  }
}

【学习笔记】Flutter重要知识点_第43张图片
【学习笔记】Flutter重要知识点_第44张图片

2.18 监听滚动(NotificationListener)

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
  ScrollController _controller = ScrollController(initialScrollOffset: 300);
  bool _isShowFloatingButton = false;

  @override
  void initState() {
    super.initState();
    _controller.addListener(() {
      // print("监听到滚动--${_controller.offset}");
      setState(() {
        _isShowFloatingButton = _controller.offset >= 1000;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    /**
     * 两种方式可以监听:
     * controller:
     *    1、设置默认值
     *    2、监听滚动,也可以监听滚动的位置
     * NotificationListener
     *    1、监听开始滚动和结束滚动
     */
    return Scaffold(
      appBar: AppBar(
        title: Text("Custom ScrollView"),
      ),
      body: NotificationListener(
        onNotification: (ScrollNotification notification) {
          if(notification is ScrollStartNotification) {
            print("开始滚动");
          } else if (notification is ScrollEndNotification) {
            print("结束滚动");
          } else if(notification is ScrollUpdateNotification) {
            print("正在滚动...,总滚动的范围为${notification.metrics.maxScrollExtent};当前滚动的像素为${notification.metrics.pixels}");
          }
          return true;
        },
        child: ListView.builder(
            controller: _controller,
            itemCount: 100,
            itemBuilder: (BuildContext ctx, int index) {
              return ListTile(
                leading: Icon(Icons.people),
                title: Text("联系人$index"),
              );
            }),
      ),
      floatingActionButton: _isShowFloatingButton
          ? FloatingActionButton(
              child: Icon(Icons.arrow_upward),
              onPressed: () {
                _controller.animateTo(0,
                    duration: Duration(seconds: 1), curve: Curves.easeIn);
              },
            )
          : null,
    );
  }
}

2.19 网络请求

config.dart

class HttpConfig {
  static const String baseURL = "https://httpin.org";
  static const int timeout = 5000;
}

http_request.dart

import 'package:dio/dio.dart';
import 'package:flutter_learn/service/config.dart';

class HttpRequest {
  static final BaseOptions baseOption = BaseOptions(
      baseUrl: HttpConfig.baseURL, connectTimeout: HttpConfig.timeout);
  static final Dio dio = Dio(baseOption);

  static Future<T> request<T>(String url, {
    String method = "get",
    required Map<String, dynamic> params,
    required Interceptor inter})  async{

    //创建单独配置
    final options = Options(method: method);

    //全局拦截器
    //创建默认的拦截器
    Interceptor dInter = InterceptorsWrapper(
      onRequest: (options, handler) {
        print("请求拦截");
        return handler.next(options);
      },
      onError: (error,handle){
        print("错误拦截");
        return handle.next(error);
      },
      onResponse: (response, handler){
        print("响应拦截");
        handler.next(response);
      }
    );
    List<Interceptor> inters = [dInter];

    //请求单独拦截器
    inters.add(inter);
    //统一添加
    dio.interceptors.addAll(inters);

    //发送网络请求
    try{
      Response response = await dio.request(url, queryParameters: params, options: options);
      //返回数据
      return response.data;
    } on DioError catch(e) {
      //返回错误
      return Future.error(e);
    }
  }
}

main.dart

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_learn/service/http_request.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("网络请求"),
      ),
      body: HYHomeContent(),
    );
  }
}

class HYHomeContent extends StatefulWidget {

  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  void initState() {
    super.initState();

    //发送网络请求
    //1、创建dio对象
    //2、发送网络请求
    final dio = Dio();
    dio.get("https://httpbin.org/get").then((value) {
      print(value);
    });
    dio.post("https://httpbin.org/post").then((value) {
      print(value);
    });
    HttpRequest.request("https://httpbin.org/get", params: {"name": "WYJ"}, inter: InterceptorsWrapper(
      onRequest: null
    )).then((value) {
      print(value);
    }).catchError((err){
      print(err);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

运行结果

Launching lib\main.dart on MIX 2S in debug mode...
Running Gradle task 'assembleDebug'...
������ʽ����ȷ -Built build\app\outputs\flutter-apk\app-debug.apk.
Debug service listening on ws://127.0.0.1:51131/opqAKK6pzn4=/ws
Syncing files to device MIX 2S...
W/Gralloc3(29843): mapper 3.x is not supported
I/flutter (29843): 请求拦截
I/flutter (29843): 响应拦截
I/flutter (29843): {args: {name: WYJ}, headers: {Accept-Encoding: gzip, Host: httpbin.org, User-Agent: Dart/2.16 (dart:io), X-Amzn-Trace-Id: Root=1-62760ff8-1a8a8c3820473ddb2fd8e98a}, origin: 39.190.86.190, url: https://httpbin.org/get?name=WYJ}
I/flutter (29843): {"args":{},"headers":{"Accept-Encoding":"gzip","Host":"httpbin.org","User-Agent":"Dart/2.16 (dart:io)","X-Amzn-Trace-Id":"Root=1-62760ff8-005c4ed00ec32e1b622c24bb"},"origin":"39.190.86.190","url":"https://httpbin.org/get"}
I/flutter (29843): {"args":{},"data":"","files":{},"form":{},"headers":{"Accept-Encoding":"gzip","Content-Length":"0","Content-Type":"application/json; charset=utf-8","Host":"httpbin.org","User-Agent":"Dart/2.16 (dart:io)","X-Amzn-Trace-Id":"Root=1-62760ff8-66ee2d1c07568fc34858e558"},"json":null,"origin":"39.190.86.190","url":"https://httpbin.org/post"}

2.20 flutter渲染流程

Widget----->Element------>Render Object(最终由Render Object渲染界面)------>layout、paint

Element层作用:增加一层类似于虚拟dom,花最小的开销修改Widget

    //组件Widget不会生成RenderObject
    Container()
    Text()

    //渲染Widget生成RenderObject
    Padding()
    Row()

Padding->SingleChildRenderObjectWidget->RenderObjectWidget->Widget
【学习笔记】Flutter重要知识点_第45张图片
在widget里面有一个重要的方法createRenderObject,这是抽象方法,查看SingleChildRenderObjectWidget,并没有实现这个方法。
【学习笔记】Flutter重要知识点_第46张图片
那么SingleChildRenderObjectWidget的子类Padding实现了这个方法
【学习笔记】Flutter重要知识点_第47张图片
Padding->RenderPadding->RenderShiftedBox->RenderBox->RenderObject

那么Element的创建呢
【学习笔记】Flutter重要知识点_第48张图片
查看Container的父类StatelessWidget
【学习笔记】Flutter重要知识点_第49张图片
凡是继承Widget,子类必然要实现CreateElement这个方法
【学习笔记】Flutter重要知识点_第50张图片
createElement创建的对象不同,比如这里的statelessWidget创建了StatelessElement
【学习笔记】Flutter重要知识点_第51张图片
查看ComponentElement
【学习笔记】Flutter重要知识点_第52张图片
【学习笔记】Flutter重要知识点_第53张图片
【学习笔记】Flutter重要知识点_第54张图片
【学习笔记】Flutter重要知识点_第55张图片
【学习笔记】Flutter重要知识点_第56张图片
【学习笔记】Flutter重要知识点_第57张图片
【学习笔记】Flutter重要知识点_第58张图片
【学习笔记】Flutter重要知识点_第59张图片
【学习笔记】Flutter重要知识点_第60张图片
最终还是调用了Widget里面的build方法,那么Widget是谁?
回到Container
【学习笔记】Flutter重要知识点_第61张图片
【学习笔记】Flutter重要知识点_第62张图片【学习笔记】Flutter重要知识点_第63张图片
【学习笔记】Flutter重要知识点_第64张图片
【学习笔记】Flutter重要知识点_第65张图片
【学习笔记】Flutter重要知识点_第66张图片
【学习笔记】Flutter重要知识点_第67张图片
可以看出这里的widget赋值给_widget

对于RenderObject
【学习笔记】Flutter重要知识点_第68张图片
【学习笔记】Flutter重要知识点_第69张图片
做的是createRenderObject的操作

【补充】为什么能在state里面获取widget
【学习笔记】Flutter重要知识点_第70张图片

2.21 key的作用

import 'dart:math';

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
  final List<String> names = ["aaaa", "bbbbb", "cccccc"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("列表测试"),
      ),
      body: ListView(
        children:
        names.map((item) {
          return ListItemLess(item);
        }).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.delete),
        onPressed: () {
          setState(() {
            names.removeAt(0);
          });
        },
      ),
    );
  }
}

class ListItemLess extends StatelessWidget {
  final String name;
  final Color randColor = Color.fromARGB(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));
  ListItemLess(this.name);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(name),
      height: 80,
      color: randColor,
      width: double.infinity,
    );
  }
}

【学习笔记】Flutter重要知识点_第71张图片
点击删除按钮,虽然删除了第一个item,但是颜色也重新build了,此时将statelessWidget转换为statefulWidget

import 'dart:math';

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
  final List<String> names = ["aaaa", "bbbbb", "cccccc"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("列表测试"),
      ),
      body: ListView(
        children:
        names.map((item) {
          return ListItemFul(item);
        }).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.delete),
        onPressed: () {
          setState(() {
            names.removeAt(0);
          });
        },
      ),
    );
  }
}

// class ListItemLess extends StatelessWidget {
//   final String name;
//   final Color randColor = Color.fromARGB(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));
//   ListItemLess(this.name);
//
//   @override
//   Widget build(BuildContext context) {
//     return Container(
//       child: Text(name),
//       height: 80,
//       color: randColor,
//       width: double.infinity,
//     );
//   }
// }

class ListItemFul extends StatefulWidget {
  final String name;

  ListItemFul(this.name);

  @override
  State<ListItemFul> createState() => _ListItemFulState();
}

class _ListItemFulState extends State<ListItemFul> {
  final Color randColor = Color.fromARGB(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(widget.name),
      height: 80,
      color: randColor,
      width: double.infinity,
    );
  }
}

【学习笔记】Flutter重要知识点_第72张图片
【学习笔记】Flutter重要知识点_第73张图片
虽然删除了第一个,但是实际效果是删除了最后一个。
原因是如图
【学习笔记】Flutter重要知识点_第74张图片
也就是说当没有key传入时,element数组默认会删除最有一个。
接下来修改代码,传入key

import 'dart:math';

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
  final List<String> names = ["aaaa", "bbbbb", "cccccc"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("列表测试"),
      ),
      body: ListView(
        children:
        names.map((item) {
          //把名字作为key
          return ListItemFul(item, key: ValueKey(item),);
        }).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.delete),
        onPressed: () {
          setState(() {
            names.removeAt(0);
          });
        },
      ),
    );
  }
}

class ListItemFul extends StatefulWidget {
  final String name;

  ListItemFul(this.name, {key}): super(key: key);

  @override
  State<ListItemFul> createState() => _ListItemFulState();
}

class _ListItemFulState extends State<ListItemFul> {
  final Color randColor = Color.fromARGB(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(widget.name),
      height: 80,
      color: randColor,
      width: double.infinity,
    );
  }
}

传入key之后,element就会对比新的和旧的,他们的key时候一致,删除第一个,那么就没有对应的element与之对应,最终留下的是第二个和第三个
【学习笔记】Flutter重要知识点_第75张图片
【学习笔记】Flutter重要知识点_第76张图片
【学习笔记】Flutter重要知识点_第77张图片
【学习笔记】Flutter重要知识点_第78张图片
回到源码,这里的canUpdate方法里面的操作,他会比较runtimeType和key

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }

key还可以强制界面刷新,比如随机生成一个不重复的key

          return ListItemFul(item, key: UniqueKey(),);

还可以传入对象生成key

          ObjectKey(对象)

GlobalKey的作用可以在Widget访问到子Widget内的属性、对象以及State内的属性和对象、子Widget的方法

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  final GlobalKey<_HYHomeContentState> homeKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: HYHomeContent(key: homeKey,),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.gesture),
        onPressed: () {
          print(homeKey.currentState?.widget.message);
          print(homeKey.currentState?.name);
        },
      ),
    );
  }
}
class HYHomeContent extends StatefulWidget {
  final String message = "aaaa";

  HYHomeContent({key}): super(key: key);

  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  final String name = "bbbb";

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

【学习笔记】Flutter重要知识点_第79张图片

2.22 共享数据

InheritedWidget

import 'package:flutter/material.dart';

main() => runApp(MyApp());

/**
 * 1、共享数据
 * 2、定义构造方法
 * 3、获取组件最近的当前InheritedWidget
 * 4、决定要不要回调State中的didChangeDependencies
 */

class HYCounterWidget extends InheritedWidget {
  final int counter;
  HYCounterWidget({required this.counter, child}): super(child: child);
  static HYCounterWidget? of(BuildContext context) {
    // 沿着Element树,去找到最近的HYCounterElement
    return context.dependOnInheritedWidgetOfExactType();
  }

  //返回true:执行依赖当前的InheritedWidget的state中的didChangeDependencies方法
  @override
  bool updateShouldNotify(HYCounterWidget oldWidget) {
    // return true;
    //判断counter是否发生改变,改变就返回true
    return oldWidget.counter != counter;
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
  int _counter = 100;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
      ),
      body: HYCounterWidget(
        counter: _counter,
        child: Column(
          children: [
            HYShowData01(),
            HYShowData02()
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          setState(() {
            this._counter++;
          });
        },
      ),
    );
  }
}
class HYShowData01 extends StatefulWidget {
  const HYShowData01({Key? key}) : super(key: key);

  @override
  State<HYShowData01> createState() => _HYShowData01State();
}

class _HYShowData01State extends State<HYShowData01> {

  // 依赖InheritedWidget(HYCounterWidget),
  // 当数据改变时,会调用这里的didChangeDependencies方法
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("执行了_HYHomePageState中的didChangeDependencies方法");
  }

  @override
  Widget build(BuildContext context) {
    int? counter = HYCounterWidget.of(context)?.counter;
    return Card(
      color: Colors.red,
      child: Text("当前计数:${counter}"),
    );
  }
}
class HYShowData02 extends StatelessWidget {
  const HYShowData02({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    int? counter = HYCounterWidget.of(context)?.counter;
    return Card(
      color: Colors.blue,
      child: Text("当前计数:${counter}"),
    );
  }
}

provider、Consumer、selector

provider.dart

import 'package:flutter/material.dart';
import 'viewmodel/initialize.dart';
import 'package:provider/provider.dart';
import 'viewmodel/01_inheritedWidget.dart';
import 'viewmodel/02_UserViewModel.dart';

/**
 * 1。创建自己需要共享的数据
 * 2.在应用程序的顶层加上ChangeNotifierProvider
 * 3.在其他位置使用共享的数据
 *  - provider.of:数据发生改变时,所在的Widget的build方法会重新执行
 *  - Consumer:只有consumer的build方法会重新构建
 *  - selector: 1.selector方法对原有数据进行转换;2、shouldRebuild是否要重新构建
 *
 *  多个共享数据使用MultiProvider
 *
 */

main() {
  runApp(
      MultiProvider(
        providers: provider,
        child: MyApp(),
      )
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(""),
        ),
        body: Column(
          children: [HYShowData01(), HYShowData02(), HYShowData03()],
        ),
        floatingActionButton:
        Selector<HYCounterViewModel, HYCounterViewModel>(
            selector: (ctx, counterVM) {
              return counterVM;
            },
            shouldRebuild: (prev, next) {
              return false;
            },
            builder: (ctx, builder, child) {
              return FloatingActionButton(
                child: child,
                onPressed: () {
                  builder.counter++;
                },
              );
            },
            child: Icon(Icons.add),
        )
      // Consumer(
      //     builder: (ctx, builder, child) {
      //       return FloatingActionButton(
      //         child: child,
      //         onPressed: () {
      //           builder.counter++;
      //         },
      //       );
      //     },
      //   child: Icon(Icons.add),,
      // )
    );
  }
}

class HYShowData01 extends StatelessWidget {
  const HYShowData01({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //拿到对象
    int counter = Provider
        .of<HYCounterViewModel>(context)
        .counter;

    return Card(
      color: Colors.blue,
      child: Text("当前计数:$counter"),
    );
  }
}

class HYShowData02 extends StatelessWidget {
  const HYShowData02({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    int counter = Provider
        .of<HYCounterViewModel>(context)
        .counter;

    return Consumer<HYCounterViewModel>(
        builder: (ctx, builder, child) {
          return Card(
            color: Colors.red,
            child: Text("当前计数:${builder.counter}"),
          );
        }
    );
  }
}

class HYShowData03 extends StatelessWidget {
  const HYShowData03({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // return Consumer(builder: (ctx, builder, child) {
    //   return Text("nickname:${builder.user.nickname}");
    // });
    return Consumer2<HYUserViewModel, HYCounterViewModel>(builder: (ctx, userVM, counterVM, child) {
      return Text("nickname:${userVM.user.nickname}, counter:${counterVM.counter}");
    });
  }
}

01_inheritedWidget.dart

import 'package:flutter/cupertino.dart';

//with是混入,如果该类已经继承其他类就不能使用extends继承,而是with混入
class HYCounterViewModel with ChangeNotifier{
  int _counter = 100;

  int get counter => _counter;

  set counter(int value) {
    _counter = value;

    //通知所有使用过counter的监听者
    notifyListeners();
  }
}

02_UserViewModel.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter_learn/%E5%AD%A6%E4%B9%A0%E6%A1%88%E4%BE%8B/24_%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86/model/user_model.dart';

class HYUserViewModel extends ChangeNotifier {
  UserInfo _user;

  HYUserViewModel(this._user);

  UserInfo get user => _user;

  set user(UserInfo value) {
    _user = value;
  }
}

initialize.dart

import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';

import '../model/user_model.dart';
import '01_inheritedWidget.dart';
import '02_UserViewModel.dart';

List<SingleChildWidget> provider = [
  ChangeNotifierProvider(create: (ctx) => HYCounterViewModel(),),
  ChangeNotifierProvider(
    create: (ctx) => HYUserViewModel(UserInfo("WYJ", 1, "1111")),)
];

【学习笔记】Flutter重要知识点_第80张图片

2.23 手势监听

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: HYGuestureDemo03(),
    );
  }
}

class HYGuestureDemo03 extends StatelessWidget {
  const HYGuestureDemo03({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Stack(
        alignment: Alignment.center,
        children: [
          GestureDetector(
            onTapDown: (detail) {
              print("outer Click");
            },
            child: Container(width: 200, height: 200, color: Colors.red)
          ),
          // IgnorePointer()  忽略手势
          GestureDetector(
            onTapDown: (detail) {
              print("inner Click");
            },
            child: Container(width: 100, height: 100, color: Colors.blue)
          ),
        ],
      ),
    );
  }
}

class HYGestureDemo02 extends StatelessWidget {
  const HYGestureDemo02({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        onTapDown: (detail) {
          print("outer Click");
        },
      child: Container(
        width: 200,
        height: 200,
        color: Colors.red,
        //这里Container嵌套Container如果不加上Aligment属性,
        // 里面的Container会扩展至外部包裹的Container大小
        alignment: Alignment.center,
        child: GestureDetector(
          onTapDown: (detail) {
            print("inner Click");
          },
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
        ),
      ),
    ));
  }
}

class HYGestureDemo extends StatelessWidget {
  const HYGestureDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        onTap: () {
          print("手势点击");
        },
        onTapDown: (detail) {
          print("手势下落");
        },
        onTapUp: (detail) {
          print("手势抬起");
        },
        onTapCancel: () {
          print("手势取消");
        },
        child: Container(
          width: 200,
          height: 200,
          color: Colors.orange,
        ),
      ),
    );
  }
}

class HYListenerDemo extends StatefulWidget {
  @override
  State<HYListenerDemo> createState() => _HYHYListenerDemoState();
}

class _HYHYListenerDemoState extends State<HYListenerDemo> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Listener(
        onPointerDown: (event) {
          print("指针按下:$event");
          print(event.position); //相对屏幕(左上角为0,0;往下为y,往右为x)
          print(event.localPosition); //相对当前组件的位置
        },
        onPointerMove: (event) {
          print("指针移动:$event");
        },
        onPointerUp: (event) {
          print("指针抬起:$event");
        },
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
        ),
      ),
    );
  }
}

2.24 多Widget之间的通信(eventBus)

import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';

/**
 * 第一步:创建全局变量evenBus
 */
final evenBus = EventBus();
class UserInfo {
  String nickname;
  int level;
  UserInfo(this.nickname, this.level);
}

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue, splashColor: Colors.transparent
        ),
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: Column(
        children: [
          HYButton(),
          HYText()
        ],
      ),
    );
  }
}

class HYText extends StatefulWidget {
  @override
  State<HYText> createState() => _HYTextState();
}

class _HYTextState extends State<HYText> {
  String _message = "Hello World";

  @override
  void initState() {
    super.initState();
    /**
     * 第三步:获取数据
     */
    evenBus.on<UserInfo>().listen((event) {
      setState(() {
        _message = "${event.nickname}-${event.level}";
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text(_message);
  }
}

class HYButton extends StatelessWidget {
  const HYButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text("按钮"),
        onPressed: () {
          /**
           * 第二步:发布数据
           */
          final info = UserInfo("WYJ", 1);
          evenBus.fire(info);
        }
    );
  }
}

2.25 路由管理

import 'package:flutter/material.dart';
import './about.dart';
import './detail.dart';
import 'error.dart';
import 'router/router.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue, splashColor: Colors.transparent,
        ),
        routes: HYRouter.routes,
      initialRoute: HYRouter.initialRoute,
      onGenerateRoute: HYRouter.generateRoute,
      onUnknownRoute: HYRouter.unknownRoute
      },
    );
  }
}

class HYHomePage extends StatefulWidget {
  static const String routerName = "/";
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
  String _message = "message";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            RaisedButton(
              child: Text("跳转至详情"),
                onPressed: () => _jumpToDetail(context)
            ),
            RaisedButton(
                child: Text("跳转至关于页面"),
                onPressed: () => _jumpToAbout(context)
            ),
            RaisedButton(
                child: Text("跳转至详情页面"),
                onPressed: () => _jumpToDetail2(context)
            ),
            RaisedButton(
                child: Text("跳转至设置页面"),
                onPressed: () => _jumpToSettings(context)
            ),
            Text(_message)
          ],
        ),
      ),
    );
  }

  void _jumpToDetail(BuildContext context) {
    //普通的跳转方式
    Future result = Navigator.of(context).push(
        MaterialPageRoute(
          builder: (ctx) {
            return HYDetailScreen("home is message");
          }
        )
    );
    result.then((value) {
      setState(() {
        _message = value;
      });
      print(value);
    });
  }

  void _jumpToAbout(BuildContext context) {
    Navigator.of(context).pushNamed(HYAboutPage.routerName, arguments: "a home message");
  }

  void _jumpToDetail2(BuildContext context) {
    Navigator.of(context).pushNamed(HYDetailScreen.routername, arguments: "a home detail2 message");
  }

  void _jumpToSettings(BuildContext context) {
    Navigator.of(context).pushNamed("/settings");
  }
}

router.dart

import 'package:flutter/material.dart';

import '../27_路由管理.dart';
import '../about.dart';
import '../detail.dart';
import '../error.dart';

class HYRouter {
  static final Map<String, WidgetBuilder> routes = {
    //命名路由
    HYHomePage.routerName: (ctx) => HYHomePage(),
    HYAboutPage.routerName: (ctx) => HYAboutPage()
  };
  static final String initialRoute = HYHomePage.routerName;

  static final RouteFactory generateRoute = (setting) {
    if (setting.name == HYDetailScreen.routername) {
      return MaterialPageRoute(
          builder: (ctx) {
            return HYDetailScreen(setting.arguments as String);
          }
      );
    }
    return null;
  };
  static final RouteFactory unknownRoute = (settings) {
    return MaterialPageRoute(
        builder: (ctx) {
          return HYErrortPage();
        }
    );
  };
}

detail.dart

import 'package:flutter/material.dart';

class HYDetailScreen extends StatelessWidget {
  static const String routername = "/detail";

  String _message;
  HYDetailScreen(this._message);
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () {
        _backToHome(context);
        /**
         * 当返回true时,可以自动返回
         * 当返回false时,自行返回代码
         */
        return Future.value(false);
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text("data"),
          // leading: IconButton(onPressed: () => {
          //   _backToHome(context)
          // }, icon: Icon(Icons.back_hand)),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(_message,style: TextStyle(fontSize: 20,color: Colors.red),),
              RaisedButton(
                  child: Text("back"),
                  onPressed: () {
                    _backToHome(context);
                  })
            ],
          ),
        ),
      ),
    );
  }

  void _backToHome(BuildContext context) {
    Navigator.of(context).pop("a detail message");
  }
}

2.26 动画Animation

import 'package:flutter/material.dart';

main() => runApp(MyApp());
/**
 * 1、Animation:抽象类
 *  - 监听动画值的改变
 *  - 监听动画状态的改变
 *  - value
 *  - status
 *
 *  2、AnimationController继承Animation
 *  - vsync:同步信号,屏幕刷新率(要持续收到同步信号才会继续绘制)
 *  - vsync:this -》with SingleTickerProviderStateMixin
 *  - forward():向前执行动画
 *  - reverse():反转执行动画
 *
 *  3、CurvedAnimation:
 *  - 作用:设置动画执行的速率(速度曲线)
 *
 *  4、Tween:设置动画执行的value范围
 *  - begin:开始的大小
 *  - end:结束时大小
 *
 */
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage>
    with SingleTickerProviderStateMixin {

  //1、创建AnimationController
  late AnimationController _controller;
  late CurvedAnimation animation;
  late Animation valueAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
        vsync: this,
        duration: Duration(seconds: 1),
        lowerBound: 0,
        upperBound: 1);

    // 2、设置Curve的值
    animation = CurvedAnimation(parent: _controller, curve: Curves.elasticInOut);

    //3、Tween
    valueAnimation = Tween(begin: 50.0, end: 150.0).animate(animation);

    // valueAnimation.addListener(() {
    //   setState(() {
    //
    //   });
    // });
    _controller.addStatusListener((status) {
      if(status == AnimationStatus.completed) {
        _controller.reverse();
      } else  if(status == AnimationStatus.dismissed){
        _controller.forward();
      }
    });
    
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print("执行_HYHomePageState的build方法");
    return Scaffold(
      appBar: AppBar(
        title: Text("动画"),
      ),
      body: Center(

        //AnimatedBuilder
        child: AnimatedBuilder(
          builder: (BuildContext context, Widget? child) {
            return Icon(Icons.favorite, color: Colors.red, size: valueAnimation.value);
          },
          animation: valueAnimation,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.abc, color: Colors.red,),
        onPressed: () {
          if(_controller.isAnimating) {
            _controller.stop();
          }else {
            _controller.forward();
          }
        },
      ),
    );
  }
}

/**
 * AnimatedWidget
 * 1、将需要执行动画的Widget放到一个AnimatedWidget中的build方法进行返回
 * 2、缺点:A、每次都需要创建一个类;B、如果够贱的Widget有子类,那么子类依然会重复构建build
 *
 * AnimatedBuilder
 * 最优选择
 */
// class HYAnimatedIcon extends AnimatedWidget {
//   final Animation valueAnimation;
//   HYAnimatedIcon(this.valueAnimation) : super(listenable: valueAnimation);
//   @override
//   Widget build(BuildContext context) {
//     return Icon(Icons.favorite, color: Colors.red, size: valueAnimation.value);
//   }
// }

2.27 交织动画

import 'dart:math';

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatefulWidget {
  @override
  State<HYHomePage> createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage>
    with SingleTickerProviderStateMixin {
  //1、创建AnimationController
  late AnimationController _controller;
  late CurvedAnimation animation;
  late Animation valueAnimation;

  //交织动画:创建多个Tween
  late Animation _sizeAnimation;
  late Animation _colorAnimation;
  late Animation _opacityAnimation;
  late Animation _radiansAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
        vsync: this,
        duration: Duration(seconds: 1),
        lowerBound: 0,
        upperBound: 1);

    // 2、设置Curve的值
    animation =
        CurvedAnimation(parent: _controller, curve: Curves.elasticInOut);

    //3、Tween
    valueAnimation = Tween(begin: 50.0, end: 150.0).animate(_controller);

    _colorAnimation =
        ColorTween(begin: Colors.blue, end: Colors.green).animate(_controller);
    _sizeAnimation = Tween(begin: 50.0, end: 150.0).animate(_controller);
    _opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(_controller);
    _radiansAnimation = Tween(begin: 0.0, end: 2.0 * pi).animate(_controller);

    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        _controller.forward();
      }
    });

    // //使用AnimatedBuilder就不需要setState
    // _controller.addListener(() {
    //   setState(() {});
    // });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print("执行_HYHomePageState的build方法");
    /**
     * 交织动画:
     * 1、大小变化动画
     * 2、颜色变化动画
     * 3、透明度变化动画
     */
    return Scaffold(
      appBar: AppBar(
        title: Text("动画"),
      ),
      body: Center(
          //AnimatedBuilder
        child: AnimatedBuilder(
          builder: (BuildContext context, Widget? child) {
            return Opacity(
              opacity: _opacityAnimation.value,
              child: Transform(
                transform: Matrix4.rotationZ(_radiansAnimation.value),
                alignment: Alignment.center, //对齐方式:以Container中心点居中对齐
                child: Container(
                  height: _sizeAnimation.value,
                  width: _sizeAnimation.value,
                  color: _colorAnimation.value,
                ),
              ),
            );
          },
          animation: _controller,
        )
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(
          Icons.abc,
          color: Colors.red,
        ),
        onPressed: () {
          if (_controller.isAnimating) {
            _controller.stop();
          } else {
            _controller.forward();
          }
        },
      ),
    );
  }
}

2.28 切换页面动画

import 'package:flutter/material.dart';
import 'modal_page.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: Center(
        child: Text("Hello World"),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Navigator.of(context).push(
            PageRouteBuilder(
              transitionDuration: Duration(seconds: 3),
                pageBuilder: (ctx, animation1, animation2) {
                  return FadeTransition(
                      opacity: animation1,
                      child: HYModalPage()
                  );
                }
            )
            // MaterialPageRoute(builder: (ctx) {
            //   return HYModalPage();
            // }),
          );
        },
      ),
    );
  }
}

import 'package:flutter/material.dart';
class HYModalPage extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.orange,
      appBar: AppBar(
        title: Text("Modal Page"),
      ),
      body: Center(
        child: Text("Modal Page"),
      ),
    );
  }
}

2.29 hero动画

import 'package:flutter/material.dart';
import 'modal_page.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue, splashColor: Colors.transparent),
        home: HYHomePage());
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: Center(
        child: GridView(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 8,
              mainAxisSpacing: 8,
              childAspectRatio: 16 / 9),
          children: List.generate(20, (index) {
            final imageURL = "https://picsum.photos/200/300?random=$index";
            return GestureDetector(
              child: Hero(
                tag: imageURL,
                child: Image.network(imageURL, fit: BoxFit.cover),
              ),
              onTap: () {
                Navigator.of(context).push(
                  PageRouteBuilder(pageBuilder: (ctx, animation1, animation2) {
                    return FadeTransition(
                      opacity: animation1,
                      child: HYModalPage(imageURL),
                    );
                  }),
                );
              },
            );
          }),
        ),
      ),
    );
  }
}

import 'package:flutter/material.dart';

class HYModalPage extends StatelessWidget {
  final String _imageURL;

  HYModalPage(this._imageURL);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Center(
        child: GestureDetector(
          child: Hero(
            tag: _imageURL,
            child: Image.network(
              _imageURL,
              fit: BoxFit.cover,
            ),
          ),
          onTap: () {
            Navigator.of(context).pop();
          },
        ),
      ),
    );
  }
}

2.30 主题

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        brightness: Brightness.light,

        //primarySwatch包含primaryColor和accentColor
        primarySwatch: Colors.blue,

        //单独设置导航栏和TabBar的颜色
        primaryColor: Colors.orange,

        //单独设置FloatingButton/Switch
        accentColor: Colors.green,

        //Button的主题
        buttonTheme: ButtonThemeData(
          height: 25,
          minWidth: 10,
          buttonColor: Colors.yellow,
        ),
        cardTheme: CardTheme(
          color: Colors.green,
        ),
        textTheme: TextTheme(
          bodyText1: TextStyle(fontSize: 16),
          bodyText2: TextStyle(fontSize: 20),
        ),
      ),
      home: HYHomePage(),
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(""),
      ),
      body: HYHomeContent(),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {},
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.ac_unit), label: "首页"),
        ],
      ),
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  State<HYHomeContent> createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        primaryColor: Colors.purple,
      ),
      child: Center(
        child: Column(
          children: [
            Text(
              "Hello World",
              style: Theme.of(context).textTheme.bodyText2,
            ),
            // Switch(value: true, onChanged: ),
          ],
        ),
      ),
    );
  }
}

屏幕适配

import 'dart:ui';
class HYSizeFit {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statueHeight;

  static double rpx;
  static double px;

  static void initialize() {
    //物理分辨率
    physicalWidth = window.physicalSize.width;
    physicalHeight = window.physicalSize.height;

    //获取dpr
    dpr = window.devicePixelRatio;
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight / dpr;

    //状态栏高度
    statueHeight = window.padding.top / dpr;

    //计算rpx的大小
    rpx = screenWidth / 750;
    px = screenWidth / 750 * 2;

  }

  //适配IOS
  static double setRpx(double size) {
    return rpx * size;
  }

  static double setPx(double size) {
    return px * size;
  }
}

3.实战

点击跳转

你可能感兴趣的:(android)