Flutter 是一个跨平台的 UI 工具集,它的设计初衷,就是允许在各种操作系统上复用同样的代码,例如 iOS 和 Android,同时让应用程序可以直接与底层平台服务进行交互。如此设计是为了让开发者能够在不同的平台上,都能交付拥有原生体验的高性能应用,尽可能地共享复用代码的同时,包容不同平台的差异。

1.Dart

1.基础

1.1入口方法

main.dart

1.1注释

//

/**/

///

1.3定义变量

var strs= “dart”;
print(strs);

1.4声明变量

字符串

String str=”dart”;

数字类型

int num = 10;

1.5修饰符

var

final 只能赋值一次不能修改

const 一开始就赋值 常量不可变

1.6声明字符串

print(“$str1$str2”)

print(str1+str2) //字符串的连接

1.7List的声明

var list

var list = ["test",20,true];
//设置存放指定类型
var list =<String>["test","test1"];

list.length;  //===>获取长度
list.add("add");   //===>添加元素

创建一个固定长度的数组

第一个参数为长度,第二个参数为填充的内容,无法增加数据,无法修改长度

void main() {
  var list=List.filled(2,"1");
  print(list);
}

1.8Map

第一种方式

var persion={
  "name":"Dart",
  "age":"8"
};
print(persion);                //输出 {name: Dart, age: 8}
print(persion['name']);        //输出 Dart
print(persion['age']);         //输出 8

第二种方式

var persion1=new Map();
persion1["name"]="张三";
persion1["age"]="9";
print(persion1);                //输出 {name: 张三, age: 9}
print(persion1['name']);        //输出 张三
print(persion1['age']);         //输出 9

1.9is判断类型

var str = '111';
if (str is String) {
    print("str is String type");
} else if (str is int) {
    print("str is int type");
} else {
    print("str is other type");
}

1.10.运算符

+-*/ %取余 ~/取整

> < <= >= == !=

&&并且 || 或者 !取反

+=,-=,*=,/=,%=,~/=

判断为空之后赋值(??=)

int b;
b??=6;   //当 b在这之前没有被赋值,则在这行代码中会被赋值
//解释:当a为null时,赋值??符号后的10给a,然后将a赋值给b.
//      当a不为null时,直接将a赋值给b
 
var a;
var b = a ?? 10;
print(b);    // 输出10

1.11.类型转换

//将字符串转换为整型
String str='111';
var myNum=int.parse(str);    //输出 111

其他类型转boolean

var mynum="";    
if (mynum.isEmpty){
    print("空");
}else{
    print("非空");
}
//  ===>空

a++

a—

自增自减运算

1.12.循环

for (int i=0;i<50;i++) while() do()while() 与java类似

void main(){
  List list = [{
    "title":"新闻1",
  },{
    "title":"新闻2",
  },{
    "title":"新闻3",
  },{
    "title":"新闻4",
  }];
    //for in 循环
  for (var ele in list) {
    print(ele["title"]);
  }
}

11.13.List

常用属性

length 长度

reversed 翻转

isEmpty 是否为空

isNotEmpty 是否不为空

//增加 add
list.add("test");
//List<T>.filled(number,ele)  填充元素
List newlist = List<String>.filled(2, "1");
//全部加入,拼接数组  addAll
list.addAll(list1);
//翻转列表
List newlist = list.reversed.toList();
//indexOf()查找元素,找不到返回-1
List list = ["1","2","3"];
print(list.indexOf("1"));
//remove()移除
list.remove("1");
//fillRange(1,2,'aaa');    从1开始到索引2,填充为'aaa'
list.fillRange(1,2,'aaa');
//insert()  在索引值插入插入
list.insert(1,"4");
//insertAll  插入全部数组
list.insertAll(1,["5","6"]);
//join拼接数组
var desc = list.join('-');
//split
var list = desc.split('-');

11.14.Set

去除数组重复的内容

Set是没有顺序且不能重复的集合,所以不能通过所有去获取值

keys 获取所有的key值

values 获取所有的value值

isEmpty 判断是否为空

isNotEmpty 判读是否不为空

11.15.遍历

1.forEach
list.forEach((value){
    print(value);
});
2.map
var newlist = list.map((value){
    return value + "6";
});
print(newlist.toList());
3.any
var res = list.any((value){
    return value>5;
});
print(res);
//有一个满足返回true
4.every
var res = list.every((value){
    return value>5;
});
print(res);
//全部满足返回true
Map person = {
    "name":"tom",
    "age":19
};
person.forEach((key,value){
    print(key.toString()+"-"+value.toString());
});

2.函数

1.定义

可以在main函数内或者main函数外

void printinfo(){
    print("test");
}
printinfo();

2.可选参数

此时的gender 和 age为可选参数

String test(String name,[String gender,int age]){
    if (age != null){
        return "name:${name},gender:${gender}";
    }
    return "name:${name},gender:${gender},age:${age}";
}

3.默认参数

String test(String name,[String gender="man",int age]){
    if (age != null){
        return "name:${name},gender:${gender}";
    }
    return "name:${name},gender:${gender},age:${age}";
}

4.命名参数

String test(String name,{String gender="man",int age}){
    if (age != null){
        return "name:${name},gender:${gender}";
    }
    return "name:${name},gender:${gender},age:${age}";
}
//调用的参数和形参名相同

5.将函数当做参数传递

fn1(fn2){
    fn2();
}

fn2(){
    print("object");
}
fn1(fn2);

6.使用匿名函数传递参数

var fn = ()=>{
    print("mytest");
};
fn3(fn){
    fn();
}
fn3(fn);

7.箭头函数

list.forEach((item)=>print(item.toString()));

8.自执行方法

((value){
    print(value);
})(2);

9.必包

void test1(){
    var a = 0;
    print(a);
    a++;
}
test1();

3.类

1.定义

class Person{
  String name = "zs";

  String email = "123@git.com";

  String address = "America";

  void getinfo(){
    print("${name}${email}${address}");
  }
}
var p1 = new Person();
print(p1.name);
p1.getinfo();

2.构造函数

Person(String name,String email,String address){
    this.name = name;
    this.email = email;
    this.address = address;
}

3.简写的构造函数

Person(this.name,this.email,this.address);

4.命名构造函数

Person.now(){
    print("命名构造函数");
}
var p = new Person.now();

5.私有成员属性,加下划线

class Person{
    //私有属性
  String _name = "zs";

  String _email = "123@git.com";

  String _address = "America";

  Person();
    //私有方法
  String _getname(){
      return this._name;
  }
  void getinfo(){
    print("${this._name}${this._email}${this._address}");
  }
}

6.get set

class Rect{
  num height;
  num width;

  Rect(this.height,this.width);
  get area{
    return height*width;
  }
  set areaheight(value){
    this.height = value;
  }
}

7.在实例化之前进行赋值操作

Rect():height=2,width=10{

}

8.静态属性和静态方法static

在属性和方法前加上static

非静态方法可以调用静态成员和非静态成员

静态方法无法访问非静态的属性和方法

9.对象操作符

?条件运算符

as 类型转换

is类型判断 Person is Object ====>true

..联级操作

var p;
//不为空才调用
p?.getinfo();
var s;
s="";
s=new Person();
(s as Person).getinfo();
//..联级操作  赋值之后进行调用方法操作
Person p = new Person();
p..name = "city"
    ..email = "123@m.com"
    ..getinfo();

4.继承

1.定义继承

class Animal{

}

class Cat extends Animal{
  
}

2.实例化子类给父类传参

class Animal{
  String name;
  String kind;

  Animal(this.name,this.kind);
  getinfo(){
    print("${name}-${kind}");
  }
}

class Cat extends Animal{
  Cat(String name,String kind):super(name,kind);
  
}

在覆写父类的方法时可以加上@override也可以不写

super.父类方法名 调用父类的方法

2.抽象类

抽象并且定义标准

父类定义一个方法不去实现,子类有不同的实现 —》 多态

abstract class Wolf{
  void run();
}

class Dog extends Wolf{
  @override
  void run(){
    print("run");
  }
}

3.一个类实现多个接口

abstract class A{
  void run();
}

abstract class B{
  void walk();
}

class C implements A,B{
  @override
  void run() {
    // TODO: implement run
  }

  @override
  void walk() {
    // TODO: implement walk
  }

}

4.mixins

mixin A{
  void run(){
    print("A");
  }
}

mixin B{
  void walk(){
      print("B");
    }
}

class C with A,B{

}

1.作为mixins的类只能继承自Object,不能继承其他类

2.作为mixins的类不能有构造函数

3.一个类可以mixins多个mixins的类

4.minxins不是继承,也不是接口,而是一种特性

C c = new C()

print(C is A)

print(c is B)

print(c is C)

  • true true true

5.泛型

1.泛型方法

   print(getData<num>(12));
}

T getData<T>(T value){
  return value;
}

2.泛型类

class MyList<T>{
  List list = <T>[];
  void add(value){
    list.add(value);
  }
}

3.泛型接口

文件缓存,内存缓存

1.getBykey 和 setBykey

abstract class Cache<T>{
  getByKey(String key);
  setByKey(String key,T value);
}

class FileCache<T> implements Cache{
  @override
  getByKey(String key) {
    return null;
  }

  @override
  setByKey(String key, value) {
    print(key +"="+ value);
  }

}

class MemoeryCache<T> implements Cache{
  @override
  getByKey(String key) {
    return null;
  }

  @override
  setByKey(String key, value) {
    print(key +"="+ value);
  }
}

3.内置库dart:io

可以使用async 和 await

async让方法变成异步

await等待异步方法的完成

4.第三方库

pub get

The official repository for Dart and Flutter packages. (pub.dev)

import '' show get;   //从一个模块仅导入get方法
import '' hiden get;    //不需要get方法
import '' deferred; //懒加载,用到才导入 

6. 2.13新特性

1.可空类型

int a=12;   //声明a为不可空类型
a = null;
//此时会报错,因为dart有Null safety
int? a=12;	//声明a为可空类型
a=null;
String test(url){
  if (url !=null){
    return 'test';
  }
  return null;
}
//报错,返回值可能为null
String? test(url){
  if (url !=null){
    return 'test';
  }
  return null;
}
//声明返回值为可空

2.类型断言

void test(String? url){
  //如果不为空会打印出长度,为空会抛出异常
    print(url!.length);
}
void test(String? url){
  //如果不为空会打印出长度,为空会抛出异常
    try{
      print(url!.length);
    }catch(error){
      print("url为空");
    }
}

3.late关键字

late关键字用来延迟初始化

class person{
  late String name;
  late String age;

  void setname(String name,String age){
    this.name = name;
    this.age = age;
  } 
}

4.require 用来标记为必填参数

void PrintTest({required String name,required String age}){

}

7.性能优化

1.常量

const PI = 3.14 –>定义常量

  • const final
  • const 声明的常量是在编译时确定的
  • final 声明的常量允许声明后再赋值,赋值后不可改变s

2.identical

var a = new Object();
var b = new Object();
print(identical(a, b)); //查看两个对象是否共用同一个内存空间
// ---->false

const 在多个地方定义相同的对象时,内存只保留了一个对象

const a = Object();
const b = Object();
print(identical(a, b)); //查看两个对象是否共用同一个内存空间
// ---->true

3.常量构造函数

常量构造函数以const开头

const 构造函数必须用于成员变量都是final的类

如果实例化不加const,即使调用的是常量构造函数 ,实例化的成员也不是常量实例对象

class person{
  final String name;
  final String age;
  const person({required this.name,required this.age});
}
const a = const person(name:"test",age:"12");
const b = const person(name:"test",age:"12");
print(identical(a, b)); //查看两个对象是否共用同一个内存空间
//---->true

2.Flutter基础

配置JDK,下载Android studio

1.配置Flutter

1.下载SDK

https://docs.flutter.dev/get-started/install/windows/mobile

2.配置镜像

PUB_HOSTED_URL:https://pub.flutter-io.cn

FLUTTER_STORAGE_BASE_URL:https://storage.flutter-io.cn

3.配置环境变量

sdk的bin目录

4.报错说需要同意证书

安装安卓命令行工具 cmdline-tools

flutter doctor –android-licenses

2.flutter项目文件

创建flutter项目

flutter create rctool

lib –> 所有的代码将会写在lib目录下

pubspec.yaml —>配置文件

3.入口main.dart

void main(){
  runApp(const Center(
    child: Text("哈哈哈",textDirection: TextDirection.ltr,style: TextStyle(
      color: Color.fromRGBO(35, 67, 188, 1), //字体颜色
      fontSize: 40   //字体大小
    ),),
  ));
}

3.Flutter组件

MaterialApp和Scaffold两个组件装饰APP

1.MaterialApp

runApp(MaterialApp(
    home: Scaffold(
        appBar: AppBar(title: Text("hello flutter")),
        body: const Center(
            child: Text("哈哈哈",textDirection: TextDirection.ltr,style: TextStyle(
                color: Color.fromRGBO(35, 67, 188, 1), //字体颜色
                fontSize: 40   //字体大小
            ))
        ))
));
}

statelessWidget 无状态组件,状态不可变的Widget

statefulWidget 状态组件,状态可能在生命周期发生改变

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

  @override
  Widget build(BuildContext context) {
    return const Center(
        child: Text("哈哈哈",textDirection: TextDirection.ltr,style: TextStyle(
            color: Color.fromRGBO(35, 67, 188, 1), //字体颜色
            fontSize: 40   //字体大小
        ))
    );
  }
}

2.Container容器组件

alignment(这个属性是针对容器中的child的对其方式)

    topCenter:顶部居中对齐
    topLeft:顶部左对齐
    topRight:顶部右对齐
    center:水平垂直居中对齐
    centerLeft:垂直居中水平居左对齐
    centerRight:垂直居中水平居右对齐
    bottomCenter底部居中对齐
    bottomLeft:底部居左对齐
    bottomRight:底部居右对齐  
    decoration(容器的修饰器,用于背景或者border)
    如果在decoration中用了color,就把容器中设置的color去掉,不要重复设置color,设置的边框样式是让四条边框的宽度为8px,颜色为黑	   色


margin(margin属性是表示Container与外部其他组件的距离)

padding(指Container边缘与Child之间的距离)
padding: EdgeInsets.all(20.0),

transform(可以根据自己的需要调整旋转的角度)

transform: Matrix4.rotationZ(0.2)

width宽度

height高度
class myApp extends StatelessWidget{
  const myApp({super.key});

  @override
  Widget build(BuildContext context) {
    return  Center(
        child: Container(
          alignment: Alignment.center,   //对齐位置
          width: 100,
          height: 100,
          //margin: EdgeInsetsGeometry.lerp(),
          decoration: BoxDecoration(
            color: Colors.red,   //背景颜色
            border: Border.all(   //边框
              color: Colors.blue,
              width: 2
            ),
            borderRadius: BorderRadius.circular(50),    //圆角
            boxShadow: const [    //配置阴影效果
              BoxShadow(color:Colors.black,
                blurRadius: 10.0
              )
            ],
            gradient: const LinearGradient(colors: [Colors.amberAccent,Colors.red])
          ),
          child: const Text("data",style: TextStyle(color: Colors.amberAccent),),
        )
    );
  }
}

margin

margin: const EdgeInsets.fromLTRB(left, top, right, bottom)

transform 移动

transform: Matrix4.translationValues(x, y, z),  //位移
transform: Matrix4.rotationX(radians),  //旋转      radians为角度
transform: Matrix4.skewX(alpha),     //缩放

3.Text组件

style 文字样式(颜色、粗细)
textAlign 文字对齐样式
overflow 文字字数超出后样式
textScaleFactor 文字大小
maxLines 最大行数

4.Image组件

1.加载远程图片

Image.network("")
child: Image.asset("assert/a8f6066ff11c400a10419beba3dd2a61.jpg",
                   fit: BoxFit.fill,
                  ),

fit 可以控制图片的填充形式,宽度填满等

实现圆角图片

decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(150),
    image: const DecorationImage(
        image: NetworkImage("https://pss.bdstatic.com/static/superman/img/logo/bd_logo1-66368c33f8.png"),
        fit:BoxFit.cover
    ),
),

ClipOval实现圆角图片

return ClipOval(
  child: Image.network("https://pss.bdstatic.com/static/superman/img/logo/bd_logo1-66368c33f8.png",
  width: 150,
    height: 150,
    fit: BoxFit.cover,
  ),
  );

2.加载本地图片

pubspec.yaml

flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  assets:
     - images/a.jpg
     - images/2.0x/a.jpg
     - images/3.0x/a.jpg

5.Icon图标

Icon(Icons.home,size: 40,color: Colors.blue,)

1.pubspec.yaml

fonts:
  - family: richuicon   //自定义字体名
    fonts:
      - asset: fonts/iconfont.ttf

2.自定义图标

class richuicon{
  static const IconData check = IconData(
      0xe645,   //unicode编码
      fontFamily: "richuicon",   //自定义的fontFamily 
      matchTextDirection: true
  );

  static const IconData close = IconData(
      0xe646,   //unicode编码
      fontFamily: "richuicon",   //自定义的fontFamily 
      matchTextDirection: true
  );
}

3.使用

Icon(richuicon.check,size: 40,color: Colors.amberAccent,)

6.ListView

1.静态

可滑动

ListView(
    children: const <Widget>[myApp(),myButton(),myImage(),Icon(Icons.home,size: 40,color: Colors.blue,),
                             Icon(richuicon.check,size: 40,color: Colors.amberAccent,)
     ],
)

scrollDirection Axis.horizationtal水平列表 Axis.vertical垂直列表

2.动态展示数据

class mylist extends StatelessWidget {

  List<Widget> initdata(){
    List<Widget> list = [];
    for (var i=0;i<10;i++){
      list.add( ListTile(
        title: Text("data$i"),
      ));
    }
    return list;
  }

  const mylist({super.key});
  @override
  Widget build(BuildContext context) {
      return ListView(
        children: initdata(),
      );
  }
}

使用ListViewBuilder

class myview extends StatelessWidget {
  List<String> list = [];

  myview({super.key}){
    for (var i=0;i<10;i++){
      list.add("data$i");
    }
  }
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: list.length,
      itemBuilder:(context,index){
        return ListTile(
          title: Text("data:${list[index]}"),
        );
      },
    );
  }
}

7.网格组件Gridview

基本用法

class mygrid extends StatelessWidget{
  const mygrid({super.key});

  @override
  Widget build(BuildContext context) {
    return GridView.count(crossAxisCount: 3,    //一行有多少Widget
      children: const [
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter),
        Icon(Icons.bike_scooter)
      ],
    );
  }
}

1、GridView.count(@required int crossAxisCount)

GridView.count的使用,需要传的是int类型的参数,也就是创建固定数量的item,crossAxisCount表示横轴item的个数(系统默认是横轴);

2、GridView.extent(@required double maxCrossAxisExtent)

GridView.extent的使用,需要传的是double类型的参数,也就是创建横轴上最大可容纳的item,maxCrossAxisExtent表示横轴item的最大宽度;

3、GridView.builder(@required this.gridDelegate,@required IndexedWidgetBuilder itemBuilder)

适用于widget数量多的时候,通过GridView.builder的使用,动态的创建widget,itemBuilder表示子widget构造器;

4、GridView.custom(@required this.gridDelegate,@required this.childrenDelegate)

GridView.custom的使用,通过两个代理方法gridDelegate和childrenDelegate来创建Gridview,其中gridDelegate是进行布局的代理,控制每列或每行的子widget的数量,以及上下左右间距和宽高比例;childrenDelegate的代理方法有两种实现方式,在使用的时候需要注意二者的区别。

属性 说明
scrollDirection 滚动方向
reverse 组件反向排序
controller 滚动控制(滚动监听)
primary 如果内容不足,则用户无法滚动 而如果[primary]为true,它们总是可以尝试滚动。
physics 滑动类型设置
AlwaysScrollableScrollPhysics 总是可以滑动
NeverScrollableScrollPhysics 禁止滚动
BouncingScrollPhysics 内容超过一屏 上拉有回弹效果
ClampingScrollPhysics 包裹内容 不会有回弹
shrinkWrap 默认false 内容适配
padding 内边距
crossAxisCount 列 数量
mainAxisSpacing 垂直子 Widget 之间间距
crossAxisSpacing 水平子 Widget 之间间距
childAspectRatio 子 Widget 宽高比例
addAutomaticKeepAlives 默认true
addRepaintBoundaries 默认true
addSemanticIndexes 默认true
cacheExtent 设置预加载的区域
children 子元素
semanticChildCount 将提供语义信息的子代数量
dragStartBehavior
GridView.builder独有属性
gridDelegate 一个控制 GridView 中子项布局的委托。
itemBuilder 遍历数返回Widget
itemCount 子控件数量

GridView.builder

lass mybuild extends StatelessWidget{

  Widget initGridData(context,index){
    return Container(
      decoration: const BoxDecoration(
        color: Colors.blueAccent
      ),
      child: Column(
        children: [
          Image.asset("images/a.jpg"),
          const Text("hahaha")
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
      return GridView.builder(
        padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
          itemCount: 10,
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
           crossAxisCount: 2,
            crossAxisSpacing: 10,
            mainAxisSpacing: 10,
            childAspectRatio: 1.2
      ), itemBuilder: initGridData);
  }
}

8.Padding组件

padding padding值,EdgeInsets设置填充的值

child 子组件

4.线性布局

1.Row组件

宽度自适应

void main(){
  runApp(MaterialApp(
      home: Scaffold(
          appBar:  AppBar(title: const Text("hello flutter")),
          body: const SizedBox(
            height: 400,
            width: 400,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,  //控制主轴的方向
              crossAxisAlignment: CrossAxisAlignment.center,  //控制侧轴对其
              children:[ IconContainer(),IconContainer(),IconContainer()],
            ),
          )
      )
    )
  );
}

class IconContainer extends StatelessWidget{
  const IconContainer({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      alignment: Alignment.center,
      decoration:const BoxDecoration(
          color:Colors.red
      ),
      child:const Icon(Icons.add,color: Colors.blueAccent,size: 32,),
    );
  }
}

2.Column布局

高度自适应

void main(){
  runApp(MaterialApp(
      home: Scaffold(
          appBar:  AppBar(title: const Text("hello flutter")),
          body: const SizedBox(
            height: 400,
            width: 400,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,  //控制主轴的方向
              crossAxisAlignment: CrossAxisAlignment.center,  //控制侧轴对其
              children:[ IconContainer(),IconContainer(),IconContainer()],
            ),
          )
      )
    )
  );
}

class IconContainer extends StatelessWidget{
  const IconContainer({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      alignment: Alignment.center,
      decoration:const BoxDecoration(
          color:Colors.red
      ),
      child:const Icon(Icons.add,color: Colors.blueAccent,size: 32,),
    );
  }
}

3.弹性布局

Expanded

flex 设置占的份数

void main(){
  runApp(MaterialApp(
      home: Scaffold(
          appBar:  AppBar(title: const Text("hello flutter")),
          body:  const Flex(
            direction: Axis.horizontal,
            children: [
              Expanded(
                  flex:1,
                  child: IconContainer()
              ),
              Expanded(
                  flex:2,
                  child: IconContainer()
              ),
            ],
          )
      )
  )
  );
}

4.Stack层叠组件

以堆的方式放入children子组件,所有的组件都堆在一起

void main(){
  runApp(MaterialApp(
      home: Scaffold(
          appBar:  AppBar(title: const Text("hello flutter")),
          body: Stack(
            children: [
                Container(
                  height: 400,
                  width: 500,
                  color: Colors.red,
                ),
                const Text("data",textAlign: TextAlign.center,)
              ],
            )
          )
      )
  );
}

Positioned

  • top
  • bottom
  • left
  • right
  • height
  • width (宽度和高度必须为固定值,不能为double.infinity)

定位类型css的position

5.Align

可以控制子组件的位置

void main(){
  runApp(MaterialApp(
      home: Scaffold(
          appBar:  AppBar(title: const Text("hello flutter")),
          body: const Align(
            alignment: Alignment.center,
            child: Text("data"),
          )
      )
  )
  );
}

6.AspectRatio

aspectRatio 宽高比

class myaspect extends StatelessWidget{
  const myaspect({super.key});

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 3/1,
      child: Container(
        color: Colors.red,
    ),
    );
  }
}

7.Card

class mycard extends StatelessWidget{
  const mycard({super.key});

  @override
  Widget build(BuildContext context) {
    return Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10)
      ),
      elevation: 10, //设置阴影深度
      margin:const EdgeInsets.fromLTRB(0, 10, 0, 0) ,
      child:  const Column(
        children: [Text("data")],
      )
    );
  }
}

8.CircleAvatar

通过CircleAvatar 实现圆形图片

class mycard extends StatelessWidget{
  const mycard({super.key});

  @override
  Widget build(BuildContext context) {
    return Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10)
      ),
      elevation: 10, //设置音乐深度
      margin:const EdgeInsets.fromLTRB(0, 10, 0, 0) ,
      child:  const Column(
        children: [Text("data"),
          CircleAvatar(
            radius: 10,
            backgroundImage: AssetImage("images/a.jpg"),
          )
        ],
      )
    );
  }
}

9.ElevatedButton,TextBtton,IconButton

class myButton extends StatelessWidget{
  const myButton({super.key});

  @override
  Widget build(BuildContext context) {
/*      return SizedBox(
        child: ElevatedButton(onPressed: (){}, child: const Text("click")),//普通按钮
      );*/
/*    return SizedBox(
      child: TextButton(onPressed: (){}, child: const Text("click")),//文本按钮
    );  */
/*    return SizedBox(
      child: OutlinedButton(onPressed: (){}, child: const Text("click")),//文本按钮
    );*/
/*    return SizedBox(
      child: IconButton(onPressed: (){}, icon:const  Icon(Icons.access_alarm)),//边框按钮
    );*/
    return SizedBox(
      child: ElevatedButton.icon(onPressed: (){}, icon:const Icon(Icons.access_alarm),label: const Text("提醒",style: TextStyle(color: Colors.red,))),//图标加文字
    );
  }
}

ButtonStyle

class myButton1 extends StatelessWidget{
  const myButton1({super.key});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: SizedBox(
        child: ElevatedButton.icon(
            style: ButtonStyle(  //设置按钮样式
                backgroundColor: WidgetStateProperty.all(Colors.amberAccent),
                foregroundColor: const WidgetStatePropertyAll(Colors.blueAccent)
            ),
            onPressed: (){},
            icon:const Icon(Icons.access_alarm),
            label: const Text("提醒",style: TextStyle(color: Colors.red,fontSize: 10))),//图标加文字,
      ),
    );
  }
}

10.Wrap组件

当x轴无法显示时可以显示到y轴

void main(){
  runApp(MaterialApp(
      home: Scaffold(
          body: ListView(
            padding: const EdgeInsets.all(10),
              children:[ Layout("热搜"),Wrap(
                spacing: 10,   //间距
                alignment: WrapAlignment.spaceAround,
                runSpacing: 10,   //间距
                children: [ElevatedButton(onPressed:(){}, child: const Text("1") ),
                  ElevatedButton(onPressed:(){}, child: const Text("2") ),
                  ElevatedButton(onPressed:(){}, child: const Text("3") ),
                  ElevatedButton(onPressed:(){}, child: const Text("4") ),
                  ElevatedButton(onPressed:(){}, child: const Text("5") ),
                  ElevatedButton(onPressed:(){}, child: const Text("6") ),
                  ElevatedButton(onPressed:(){}, child: const Text("7") ),
                  ElevatedButton(onPressed:(){}, child: const Text("8") ),
                  ElevatedButton(onPressed:(){}, child: const Text("9") ),
                ],
              ),const SizedBox(height: 10,),
                Layout("历史记录"),
                const Divider(),
                const Column(
                  children: [ListTile(title: Text("5"),
                  ),Divider(),
                    ListTile(title: Text("6")),
                    Divider()
                  ],
                )
              ],
          )
      )
  )
  );
}

class Layout extends StatelessWidget{
  var text;
  Layout(this.text,{super.key});

  @override
  Widget build(BuildContext context) {
      return Row(
        children: [
          Text(text,style: Theme.of(context).textTheme.titleLarge,)
        ],
      );
  }

}

5.StatefulWidget有状态组件

实现点击按钮++

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();
}

class _HomeState extends State<HomeState>{
  int _num = 0;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text("$_num"),
          const SizedBox(height: 10,),
          ElevatedButton(onPressed: (){
            setState(() {
              _num++;
            });

          }, child:const Text("++"))
        ],
      ),
    );
  }
}

添加一个浮动按钮

void main(){
  runApp(
     MaterialApp(
      title: "richu",
      home: Scaffold(
        body:HomeState(),
        floatingActionButton: FloatingActionButton(onPressed: (){
          
        },child: Text("click  me"),),
      ),
    )
  );
}

实现动态列表

void main(){
  runApp(
     const MaterialApp(
      title: "richu",
      home: HomeState()
     ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}

class _HomeState extends State<HomeState>{
  final List<String> _list = [];
  int num = 1;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(onPressed: (){
        setState(() {
          _list.add("data$num");
          num++;
        });
      },child: const Text("+"),),
      appBar: AppBar(title:const Text("richu")),
      body: ListView(
        children:_list.map((v){
            return ListTile(
              title: Text(v),
            );
        }).toList()
      ),
    );
  }
}

1.BottomNavigationBar

自定义底部导航栏

items 配置底部菜单项

Ontab 点击事件

curretIndex 索引

Iconsize 底部图标的大小

fixedColor 选中的颜色

type:BottomNavigationBarType.fixed 如果菜单超过三个则需要加上这个

void main(){
  runApp(
     const MaterialApp(
      title: "richu",
      home: HomeState()
     ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}

class _HomeState extends State<HomeState>{
  int currentId = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(onTap: (index){
        setState(() {
          currentId = index;
        });
      },currentIndex: currentId,items: const[
        BottomNavigationBarItem(icon: Icon(Icons.home),label: "首页"),
        BottomNavigationBarItem(icon: Icon(Icons.settings),label: "设置"),
        BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),label: "用户")]),
      appBar: AppBar(title:const Text("richu")),
      body: const Text("data")
    );
  }
}

2.实现页面切换

import 'package:flutter/material.dart';
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';

void main(){
  runApp(
     const MaterialApp(
      title: "richu",
      home: HomeState()
     ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}

class _HomeState extends State<HomeState>{
  int currentId = 0;
  final List<Widget> _list = const [
    MyHomePage(),
    SettingPage(),
    UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(onTap: (index){
        setState(() {
          currentId = index;
        });
      },currentIndex: currentId,items: const[
        BottomNavigationBarItem(icon: Icon(Icons.home),label: "首页"),
        BottomNavigationBarItem(icon: Icon(Icons.settings),label: "设置"),
        BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),label: "用户")]),
      appBar: AppBar(title:const Icon(Icons.arrow_back)),
      body: _list[currentId]
    );
  }
}

3.FloatingActionButton实现底部突起按钮

shape:const CircleBorder()

void main(){
  runApp(
     const MaterialApp(
      title: "richu",
      home: HomeState()
     ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}

class _HomeState extends State<HomeState>{
  int currentId = 0;
  final List<Widget> _list = const [
    MyHomePage(),
    SettingPage(),
    UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(onTap: (index){
        setState(() {
          currentId = index;
        });
      },currentIndex: currentId,fixedColor: Colors.blue,type: BottomNavigationBarType.fixed,items: const[
        BottomNavigationBarItem(icon: Icon(Icons.home),label: "首页"),
        BottomNavigationBarItem(icon: Icon(Icons.settings),label: "设置"),
        BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),label: "用户"),
        //BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),label: "用户")
      ]),
      appBar: AppBar(title:const Icon(Icons.arrow_back)),
      floatingActionButton: Container(
          height: 60,
          width: 60,
          decoration:BoxDecoration(
            color: Colors.black12,
            borderRadius: BorderRadius.circular(30)
          ),
          child: FloatingActionButton(shape:const CircleBorder(),onPressed: (){
            setState(() {
              currentId = 1;
            });
          },child: const Icon(Icons.add),),),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        body: _list[currentId]
    );
  }
}

4.Drawer侧边栏

void main(){
  runApp(
     const MaterialApp(
      title: "richu",
      home: HomeState()
     ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}


class _HomeState extends State<HomeState>{
  int currentId = 0;
  final List<Widget> _list = const [
    MyHomePage(),
    SettingPage(),
    UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: const Drawer(
        child: Column(
          children: [
            DrawerHeader(child: ListTile(leading: Icon(Icons.home),title: Text("信息"),
              
            )),
            Divider(),
            ListTile(
            leading: CircleAvatar(child:Icon(Icons.supervised_user_circle)),
            title: Text("用户中心"),
          ),Divider(),
            ListTile(
              leading: CircleAvatar(child:Icon(Icons.delete)),
              title: Text("删除"),
            ),Divider()
          ],
        ),
      ),
        bottomNavigationBar: BottomNavigationBar(onTap: (index){
          setState(() {
            currentId = index;
          });
        },currentIndex: currentId,fixedColor: Colors.blue,type: BottomNavigationBarType.fixed,items: const[
          BottomNavigationBarItem(icon: Icon(Icons.home),label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.settings),label: "设置"),
          BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),label: "用户"),
        ]),
        appBar: AppBar(title:const Icon(Icons.arrow_back)),
        body: _list[currentId]
    );
  }
}

5.UserAccountDrawHeader

class _HomeState extends State<HomeState>{
  int currentId = 0;
  final List<Widget> _list = const [
    MyHomePage(),
    SettingPage(),
    UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: const Drawer(
        child: Column(
          children: [
            /*DrawerHeader(child: ListTile(leading: Icon(Icons.home),title: Text("信息"),

            )),*/
            UserAccountsDrawerHeader(accountName: Text("日初"), accountEmail: Text("xxx@163.com"),currentAccountPicture:CircleAvatar(backgroundImage: AssetImage("images/a.jpg"))),
            Divider(),
            ListTile(
            leading: CircleAvatar(child:Icon(Icons.supervised_user_circle)),
            title: Text("用户中心"),
          ),Divider(),
            ListTile(
              leading: CircleAvatar(child:Icon(Icons.delete)),
              title: Text("删除"),
            ),Divider()
          ],
        ),
      ),
        bottomNavigationBar: BottomNavigationBar(onTap: (index){
          setState(() {
            currentId = index;
          });
        },currentIndex: currentId,fixedColor: Colors.blue,type: BottomNavigationBarType.fixed,items: const[
          BottomNavigationBarItem(icon: Icon(Icons.home),label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.settings),label: "设置"),
          BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),label: "用户"),
        ]),
        appBar: AppBar(title:const Icon(Icons.arrow_back)),
        body: _list[currentId]
    );
  }
}

6.Bar

1.AppBar

debugShowCheckedModeBanner: false 关闭debug图标

void main(){
  runApp(
     const MaterialApp(
       debugShowCheckedModeBanner: false,
      title: "richu",
      home: HomeState()
     ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}

class _HomeState extends State<HomeState>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          leading: IconButton(onPressed: (){}, icon: const Icon(Icons.menu)), //左侧的按钮图标,
          actions: [
            IconButton(onPressed: (){}, icon: const Icon(Icons.add))  //右侧图标
          ],
        ),
        body:const Text("data")
    );
  }
}

2.TabBar

tabbar和tabbarView都要配置Controller

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin{
  late TabController _tabController;
  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          leading: IconButton(onPressed: (){}, icon: const Icon(Icons.menu)), //左侧的按钮图标,
          actions: [
            IconButton(onPressed: (){}, icon: const Icon(Icons.add))  //右侧图标
          ],
          bottom: TabBar(controller:_tabController ,tabs:const  [
            Tab(child: Text("推荐")),Tab(child: Text("热门")),Tab(child: Text("视频"),)
          ]),
        ),
        body:TabBarView(controller: _tabController ,children:const  [ListTile(
          title: Text("我的推荐"),
        ),
        ListTile(
          title: Text("我的热门"),
        ),
          ListTile(
            title: Text("我的视频"),
          )
        ])
    );
  }
}

3.AppBar属性

字段 属性 描述
key Key 当组件在组件树中移动时使用Key可以保持组件之前状态
leading Widget 通常情况下返回一个返回键(IconButton)
leadingWidth double 左侧leading的宽度,默认56
automaticallyImplyLeading bool 和leading配合使用,如果为true并且leading为空的情况下,会自动配置返回键
title Widget 导航栏的标题
centerTitle bool 标题是否居中,不同操作系统默认显示位置不一样
actions List 一个Widget列表
bottom PreferredSizeWidget 出现在导航栏底部的控件
elevation double 控制导航栏下方阴影的大小
shadowColor Color 控制导航栏下方阴影的颜色
shape ShapeBorder 导航栏的形状以及阴影
backgroundColor Color 导航栏的背景颜色
foregroundColor(只有当14属性设置为flase的时候,该属性才会生效) ) Color 导航栏中文本和图标的颜色
backwardsCompatibility bool 与foregroundColor配合使用
iconTheme IconThemeData 导航栏图标的颜色、透明度、大小的配置
actionsIconTheme IconThemeData 导航栏右侧图标的颜色、透明度、大小的配置
textTheme TextTheme 导航栏文本的排版样式
primary bool 导航栏是否显示在屏幕顶部
excludeHeaderSemantics bool 标题是否应该用 [Semantics] 包裹,默认false
titleSpacing double title内容的间距
toolbarOpacity double 导航栏的透明度
toolbarHeight double 导航栏的高度,默认kToolbarHeight
toolbarTextStyle TextStyle 导航栏图标的颜色
titleTextStyle TextStyle 导航栏标题的默认颜色
flexibleSpace Widget 堆叠在工具栏和选项卡栏的后面
systemOverlayStyle SystemUiOverlayStyle 叠加层的样式
brightness Brightness 导航栏的亮度,改属性已废弃,用systemOverlayStyle代替
bottomOpacity double 导航栏底部的透明度

3.PreferredSize配置appBar的高度

appBar: PreferredSize(preferredSize: const Size.fromHeight(50), child: TabBar(
            controller:_tabController ,
            indicatorColor: Colors.red,
            labelColor: Colors.black87,
            tabs:const  [
              Tab(child: Text("推荐")),Tab(child: Text("热门")),Tab(child: Text("视频"),)
            ]),),

4.自定义缓存组件

class KeepAliveWrapper extends StatefulWidget{
  final Widget? child;
  final bool keepAlive;
  const KeepAliveWrapper({Key? key,required this.child,this.keepAlive=true}):super(key: key);

  @override
  State<KeepAliveWrapper> createState() => _KeepAliveWrapper();

}

class _KeepAliveWrapper extends State<KeepAliveWrapper> with AutomaticKeepAliveClientMixin{
  @override
  Widget build(BuildContext context) {
      return widget.child!;
  }

  @override
  bool get wantKeepAlive => widget.keepAlive;
}

实现页面的缓存

import 'package:flutter/material.dart';

class KeepAliveWrapper extends StatefulWidget{
  final Widget? child;
  final bool keepAlive;
  const KeepAliveWrapper({Key? key,required this.child,this.keepAlive=true}):super(key: key);

  @override
  State<KeepAliveWrapper> createState() => _KeepAliveWrapper();

}

class _KeepAliveWrapper extends State<KeepAliveWrapper> with AutomaticKeepAliveClientMixin{
  @override
  Widget build(BuildContext context) {
      return widget.child!;
  }

  @override
  bool get wantKeepAlive => widget.keepAlive;
}

void main(){
  runApp(
      const MaterialApp(
          debugShowCheckedModeBanner: false,
          title: "richu",
          home: HomeState()
      ));
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=> _HomeState();

}

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin{
  late TabController _tabController;
  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: PreferredSize(preferredSize: const Size.fromHeight(50), child: TabBar(
            controller:_tabController ,
            indicatorColor: Colors.red,
            labelColor: Colors.black87,
            tabs:const  [
              Tab(child: Text("推荐")),Tab(child: Text("热门")),Tab(child: Text("视频"),)
            ]),),
        backgroundColor: Colors.white,
        body:TabBarView(controller: _tabController ,children:[KeepAliveWrapper(child: ListView(children: const [ListTile(
          title: Text("我的推荐"),
        )],),),
          const ListTile(
            title: Text("我的热门"),
          ),
          const ListTile(
            title: Text("我的视频"),
          )
        ])
    );
  }
}

5.tabController实现事件监听

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin{
  late TabController _tabController;
  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener((){
      print(_tabController.index);  //触发两次
    });
  }

解决触发两次的问题

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin{
  late TabController _tabController;
  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener((){
      if (_tabController.index == _tabController.animation!.value){
        print(_tabController.index);  //触发一次
      }
    });
  }

7.路由

1.Navigator.of(context).push()

可以通过Navigator.push()跳转到另一个页面

Navigator.pop()返回

class UserPage extends StatefulWidget{
  const UserPage({super.key});
  @override
  State<UserPage> createState() => _UserPage();
}

class _UserPage extends State<UserPage>{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          ElevatedButton(onPressed: (){
            Navigator.of(context).push(
              MaterialPageRoute(builder: (BuildContext builde){
                return const MyHomePage();
              })
            );
          }, child: const Text("搜索"))
        ],
      )
    );
  }
}

2.基本路由

可以使用widget.属性获取父类的属性

class SettingPage extends StatefulWidget{
  final String title;
  const SettingPage({super.key,this.title = ""});
  @override
  State<SettingPage> createState() => _SettingPage();
}

class _SettingPage extends State<SettingPage>{
  @override
  Widget build(BuildContext context) {
      return Center(
        child: Text(widget.title),
      );
  }
}

此时传递参数,在构造函数传递title即可

ElevatedButton(onPressed: (){
    Navigator.of(context).push(
        MaterialPageRoute(builder: (BuildContext builde){
            return const SettingPage(title: "我是设置");
        })
    );
}, child: const Text("设置"))],

3.命名路由

ElevatedButton(onPressed: (){
    Navigator.pushNamed(context, "/setting");
}, child: const Text("设置"))
    ],

4.命名路由传值

1.配置Map routes

Map routes = {
    "/" : (context) => const MyHomePage(),
    "/news" : (context) => const NewsPage(),
    "/setting" : (context,arguments) => SettingPage(arguments: arguments),
};

2.配置onGenerateRoute

//固定写法
onGenerateRoute: (RouteSettings settings){
    final String? name = settings.name;
    final Function? builder = routes[name];
    if (builder != null){
        if (settings.arguments != null){
            final Route route = MaterialPageRoute(
                builder: (context) => builder(context,arguments:settings.arguments)
            );
            return route;
        }else{
            final Route route = MaterialPageRoute(
                builder: (context) => builder(context)
            );
            return route;
        }
    }

3.传递参数arguments

ElevatedButton(onPressed: (){
    Navigator.pushNamed(context, "/news",arguments: {
        "title":"我是新闻",
        "aid":20
    });
}, child: const Text("新闻"))

4.flutter返回上一级路由

Navigator.of(context).pop();

5.替换路由

return ListView(
    children: [Text(widget.arguments["title"]),ElevatedButton(onPressed: (){
        Navigator.of(context).pushReplacementNamed("/");
    }, child: const Text("注册"))],
);

6.返回根目录

Navigator.of(context).pushAndRemoveUntil(newRoute, predicate);

7.使用IOS风格的路由跳转

import 'package:flutter/cupertino.dart';

onGenerateRoute: (RouteSettings settings){
    final String? name = settings.name;
    final Function? builder = routes[name];
    if (builder != null){
        if (settings.arguments != null){
            final Route route = CupertinoPageRoute(
                builder: (context) => builder(context,arguments:settings.arguments)
            );
            return route;
        }else{
            final Route route = CupertinoPageRoute(
                builder: (context) => builder(context)
            );
            return route;
        }
    }
    return null;
},

8.Dialog

1.AlertDialog

class NewsPage extends StatefulWidget{
  final Map arguments;
  const NewsPage({super.key,required this.arguments});

  @override
  State<NewsPage> createState() => _NewsPage();
}

class _NewsPage extends State<NewsPage>{
  @override
  Widget build(BuildContext context) {
    void _alertDialog(){
      showDialog(context: context, builder: (context){
        return AlertDialog(
          title: const Text("提示信息"),
          content: const Text("确定?"),
          actions: [
            TextButton(onPressed: (){
              Navigator.of(context).pop("ok");
            }, child: const Text("确定")),
            TextButton(onPressed: (){
              Navigator.of(context).pop("none");
            }, child: const Text("取消"))
          ],
        );
      });
    }

      return ListView(
        children: [Text(widget.arguments["title"]),ElevatedButton(onPressed: (){
          Navigator.of(context).pushReplacementNamed("/");
          //Navigator.of(context).pushAndRemoveUntil(newRoute, predicate);
        }, child: const Text("注册")),ElevatedButton(onPressed: (){
            _alertDialog();
        }, child: const Text("取消"))],
      );
  }
}

2.异步获取消息

Widget build(BuildContext context) {
    void _alertDialog() async {
        var res = await showDialog(context: context, builder: (context){
            return AlertDialog(
                title: const Text("提示信息"),
                content: const Text("确定?"),
                actions: [
                    TextButton(onPressed: (){
                        Navigator.of(context).pop("ok");
                    }, child: const Text("确定")),
                    TextButton(onPressed: (){
                        Navigator.of(context).pop("none");
                    }, child: const Text("取消"))
                ],
            );
        });
        print(res);
    }

3.SimpleDialog

void _simpleDialog()async {
  var res = await showDialog(context: context, builder: (context){
    return SimpleDialog(
      title: const Text("提示信息"),
      children: [
        SimpleDialogOption(
          onPressed: (){
            Navigator.pop(context,"1");
          },
          child: const Text("1"),
        ),
        SimpleDialogOption(
          onPressed: (){
            Navigator.pop(context,"2");
          },
          child: const Text("2"),
        ),
        SimpleDialogOption(
          onPressed: (){
            Navigator.pop(context,"3");
          },
          child: const Text("3"),
        ),
      ],
    );
  });
  print(res);
}

4.showModalBottomSheet

void _modelDialog()async {
      var res = await showModalBottomSheet(context: context, builder: (context){
        return  Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ListTile(
              title: const Text("test1"),
              onTap: (){
                Navigator.pop(context,"test1");
              },
            ),
            ListTile(
              title: const Text("test2"),
              onTap: (){
                Navigator.pop(context,"test2");
              },
            ),
            ListTile(
              title: const Text("test3"),
              onTap: (){
                Navigator.pop(context,"test3");
              },
            )
          ],
        );
      });
      print(res);
    }

5.showToast

添加配置

dependencies:
  flutter:
    sdk: flutter
  fluttertoast: ^8.0.9
Fluttertoast.showToast(
    msg: "This is Center Short Toast",  //信息
    toastLength: Toast.LENGTH_SHORT, //安卓平台生效
    gravity: ToastGravity.CENTER, //提示的位置
    timeInSecForIosWeb: 1, //提示时间web ios
    backgroundColor: Colors.red, //背景颜色
    textColor: Colors.white,  //文本颜色
    fontSize: 16.0 //字体大小 
);

6.自定义dialog

自定义dialog,并且点击按钮关闭

class Mydialog extends Dialog{
  const Mydialog({super.key});

  @override
  Widget build(BuildContext context){
    return Material(
      child: Center(
        child: Container(
          height: 300,
          width: 300,
          color: Colors.white,
          child: Column(
            children: [
              const SizedBox(height: 20,),
              Stack(
                children: [
                  const Align(alignment: Alignment.centerLeft,child: Text("提示"),),
                  Align(alignment: Alignment.centerRight,child: InkWell(child:const Icon(Icons.star_border_purple500),onTap: (){
                      //点击按钮关闭
                    Navigator.pop(context);
                  },))
                ],
              ),
              const Divider(),
              const SizedBox(height: 10,),
               Container(
                padding: const EdgeInsets.all(10),
                width: double.infinity, child: const Text("提示信息",style: TextStyle(
                fontSize: 40
              ),),
              )
            ],
          ),
        ),
      )
    );
  }
}

传递方法和参数

使用dialog

void _mydialog() {
    showDialog(context: context, builder:(context){
        return Mydialog(title:"提示",content:"我是提示",onTab: (){
            //点击按钮关闭
            Navigator.pop(context);
            print("关闭");
        },);
    });
}
class Mydialog extends Dialog{
  String title;
  String content;
  final Function()? onTab;
  Mydialog({required this.onTab, required this.title,required this.content,super.key});

  @override
  Widget build(BuildContext context){
    return Material(
      type: MaterialType.transparency,
      child: Center(
        child: Container(
          height: 300,
          width: 300,
          color: Colors.white,
          child: Column(
            children: [
              const SizedBox(height: 20,),
              Stack(
                children: [
                  Align(alignment: Alignment.centerLeft,child: Text(title),),
                  Align(alignment: Alignment.centerRight,child: InkWell(onTap: onTab!(), child:const Icon(Icons.star_border_purple500)))
                ],
              ),
              const Divider(),
              const SizedBox(height: 10,),
               Container(
                padding: const EdgeInsets.all(10),
                width: double.infinity, child:  Text(content,style: const TextStyle(
                fontSize: 40
              ),),
              )
            ],
          ),
        ),
      )
    );
  }
}

9.PageView

1.PageView

import 'package:flutter/material.dart';

class MyPageView extends StatefulWidget{
  const MyPageView({super.key});

  @override
  State<MyPageView> createState() => _MyPageView();

}

class _MyPageView extends State<MyPageView>{


  @override
  Widget build(BuildContext context) {
      return Scaffold(
        body: PageView(
          children: [
            Center(
              child: Text("1",style: Theme.of(context).textTheme.headlineLarge),
            ),
            Center(
              child: Text("2",style: Theme.of(context).textTheme.headlineLarge),
            ),
            Center(
              child: Text("3",style: Theme.of(context).textTheme.headlineLarge),
            ),
            Center(
              child: Text("4",style: Theme.of(context).textTheme.headlineLarge),
            ),
          ],
        ),
      );
  }
}

2.PageView.Builder

return PageView.builder(
    itemCount: 10,
    itemBuilder: (context,index){
        return Center(
            child: Text("data${index+1}",style: Theme.of(context).textTheme.headlineLarge)
        );
    }
);

allowImplicitScrolling 缓存当前页面的前后两页

onpageChanged(index){ //页面改变时触发

}

3.轮播图

创建定时器

//创建定时器
Timer timer = Timer.periodic(const Duration(seconds: 3),(timer){
    print("执行");
});
class MyPageView extends StatefulWidget{
  const MyPageView({super.key});

  @override
  State<MyPageView> createState() => _MyPageView();

}

class _MyPageView extends State<MyPageView>{

  var _pageController;
  late Timer timer;
  var _currentIndex;
  @override
  void initState() {
    super.initState();
    //pageController
    _pageController =PageController(initialPage: 0);
    //创建定时器
    timer = Timer.periodic(const Duration(seconds: 3),(timer){
      _pageController.animateToPage((_currentIndex+1)%10, uration: const Duration(milliseconds: 400), curve: Curves.linear,);
    });
  }

  @override
  Widget build(BuildContext context) {

    return PageView.builder(
        controller: _pageController,
        itemCount: 10,
        itemBuilder: (context,index){
          return Center(
            child: Text("data${index+1}",style: Theme.of(context).textTheme.headlineLarge)
          );
      }
    );
  }

  @override
  void dispose() {
    super.dispose();
    timer.cancel();
    _pageController.dispose();
  }


}

4.AutomaticKeepAliveClientMixin

class _MyPageView extends State<MyPageView> with AutomaticKeepAliveClientMixin{

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;

}

10.Flutter Key的作用

1.key的使用

void main(){
  runApp(const HomeState());
}

class HomeState extends StatefulWidget{
  const HomeState({super.key});

  @override
  State<HomeState> createState()=>_HomeState();
}

class _HomeState extends State<HomeState>{
  List<Widget> list = [
    const Boxed(color: Colors.red),
    const Boxed(color: Colors.yellow),
    const Boxed(color: Colors.blue,)
  ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        floatingActionButton: FloatingActionButton(child: const Icon(Icons.refresh),onPressed: (){
          setState(() {
            list.shuffle();
          });
        }),
        appBar: AppBar(
          title: const Text("标题"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: list
          ),
        ),
      )
    );
  }

}

class Boxed extends StatefulWidget{
  final Color color;
  
  const Boxed({super.key,required this.color});

  @override
  State<Boxed> createState() => _Boxed();
}

class _Boxed extends State<Boxed>{
  int _cout = 0;
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 100,
      width: 100,
      child: ElevatedButton(
          style: ButtonStyle(
            backgroundColor: WidgetStateProperty.all(widget.color)
          ),
          onPressed: (){
            setState(() {
              _cout++;
            });
          },
          child: Text("$_cout",style: Theme.of(context).textTheme.headlineLarge,)),
    );
  }
}

当点击按钮改变顺序时数字没有跟着一起变

LocalKey局部键

Globalkey全局键

List<Widget> list = [
    const Boxed(key: ValueKey("1"),color: Colors.red),
    const Boxed(key: ValueKey("2"),color: Colors.yellow),
    const Boxed(key: ValueKey("3"),color: Colors.blue,)
];

获取屏幕方向

print(MediaQuery.of(context).orientation);

2.父widget获取子widget的状态和方法

给子widget传递globalkey使用globalkey获取子组件

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

  @override
  State<HomeState> createState()=>_HomeState();
}

class _HomeState extends State<HomeState>{
  final GlobalKey _globalKey = new GlobalKey();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
          floatingActionButton:FloatingActionButton(onPressed: (){
            var BoxState = _globalKey.currentState as _Boxed;
            print(BoxState._cout);
          }),
          appBar: AppBar(
            title: const Text("标题"),
          ),
          body: Boxed(key: _globalKey,color: Colors.red)
        )
    );
  }
}

11.AnimatedList实现动态列表

class _HomeState extends State<HomeState>{
  List<String> list = ["第一","第二"];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
          floatingActionButton:FloatingActionButton(onPressed: (){
            setState(() {
              list.add("value");
            });
          },child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: AnimatedList(initialItemCount: list.length,itemBuilder: ((context,index,animation){
              return FadeTransition(opacity: animation,
                child: ListTile(title: Text(list[index]),),
              );
            }))
        )
    );
  }
}

增加数据要使用insertItem

class _HomeState extends State<HomeState>{
  final _globalKey = GlobalKey<AnimatedListState>();
  List<String> list = ["第一","第二"];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
          floatingActionButton:FloatingActionButton(onPressed: (){
            setState(() {
              list.add("value");
              _globalKey.currentState!.insertItem(list.length-1);
            });
          },child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: AnimatedList(
              key: _globalKey,
                initialItemCount: list.length,itemBuilder: ((context,index,animation){
              return FadeTransition(opacity: animation,
                child: ListTile(title: Text(list[index]),),
              );
            }))
        )
    );
  }
}

删除数据使用removeItem

_globalKey.currentState!.removeItem(list.length-1,(context,animation){
    return FadeTransition(opacity: animation,child: widget,);
});

12.flutter动画组件

1.隐式动画

在动画组件内,直接配置curve和duration属性

AnimatedContainer

使用AnimatedContainer组件,配置curve曲线过渡和duration过渡时间

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

  @override
  State<HomeState> createState()=>_HomeState();
}

class _HomeState extends State<HomeState>{
  bool press = false;   //设置动画触发的条件
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              setState(() {
                  press = true; //点击FloatingActionButton进行动画效果
                });
              }
            ,child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: AnimatedContainer(
                curve: Curves.ease, //曲线
                duration: const Duration(seconds: 1), //延时
                width: press ? 200 : 300,
                height: 200,
                color:Colors.yellow,
                  transform: press ? Matrix4.translationValues(0, 0, 0) : 
                                    Matrix4.translationValues(100, 100, 0)
              ),
            )
        )
    );
  }
}

AnimatedPadding

通过配置padding值的改变,引起组件的移动动画效果,同样支持curve和duration的配置

class _HomeState extends State<HomeState>{
  bool press = false;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              setState(() {
                press = true;
              });
            }
              ,child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: AnimatedPadding(
                padding: EdgeInsets.fromLTRB(10, press ? 10 : 400, 0, 0), //配置边距值
                  curve: Curves.ease, //曲线
                  duration: const Duration(seconds: 1), //延时
                  child: Container(
                      width: 200,
                      height: 200,
                      color:Colors.yellow,
                  ),
              ),
            )
        )
    );
  }
}

AnimatedAlign

通过配置alignment值的改变,引起组件的对齐动画效果,同样支持curve和duration的配置

class _HomeState extends State<HomeState>{
  bool press = false;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              setState(() {
                press = true;
              });
            }
              ,child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: AnimatedAlign(
                alignment: press ? Alignment.center : Alignment.topCenter,
                curve: Curves.ease, //曲线
                duration: const Duration(seconds: 1), //延时
                child: Container(
                  width: 200,
                  height: 200,
                  color:Colors.yellow,
                ),
              ),
            )
        )
    );
  }
}

AnimatedOpacity

通过配置opacity值的改变,引起组件的透明度变化动画效果,同样支持curve和duration的配置

class _HomeState extends State<HomeState>{
  bool press = false;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              setState(() {
                press = true;
              });
            }
              ,child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: AnimatedOpacity(
                opacity: press ? 1 : 0.1,
                curve: Curves.ease, //曲线
                duration: const Duration(seconds: 1), //延时
                child: Container(
                  width: 200,
                  height: 200,
                  color:Colors.yellow,
                ),
              ),
            )
        )
    );
  }
}

AnimatedPositioned

通过配置top,left,right,bottom值的改变,引起组件的距离变化动画效果,同样支持curve和duration的配置

class _HomeState extends State<HomeState>{
  bool press = false;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              setState(() {
                press = true;
              });
            }
              ,child: const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body:Stack(
              children: [
                AnimatedPositioned(
                  top: press ? 0 : 100,
                  left:press ? 0 : 100,
                  curve: Curves.ease, //曲线
                  duration: const Duration(seconds: 1), //延时
                  child: Container(
                    width: 200,
                    height: 200,
                    color:Colors.yellow,
                  ),
                ),
              ],
            )
        )
    );
  }
}

2.显示动画

使用显示动画,定义AnimationController,在组件上with SingleTickerProviderStateMixin

RotationTransition

RotationTransition实现旋转动画,turns为AnimationController,可以在initState初始化的时候设置vsync,duration来让程序和手机的刷新频率统一,使用..联级操作调用repeat函数让动画重复运动

class _Boxed extends State<Boxed> with SingleTickerProviderStateMixin{
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
        vsync: this,
        duration: const Duration(seconds: 1)
    )..repeat(); //让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
          height: 100,
          width: 100,
          child: RotationTransition(turns: _controller,
            child: const FlutterLogo(size: 60),
          )
    );
  }
}

AnimationController

controller的播放方式

repeat 重复

forward 播放一次

reverse 倒序播放

stop 停止

reset 重置

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
    AnimationController(vsync: this, duration: const Duration(seconds: 1));//让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
          floatingActionButton:FloatingActionButton(onPressed: (){
            _controller.repeat(); //重复播放
          },child:const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
                child: Column(
                    children: [RotationTransition(
                      turns: _controller,
                      child: const FlutterLogo(size: 60),
                    ),
                    ElevatedButton(onPressed: (){
                      _controller.forward(); //播放一次
                    }, child:const Icon(Icons.refresh)),
                      ElevatedButton(onPressed: (){
                        _controller.reverse(); //倒序播放
                      }, child:const Icon(Icons.refresh)),
                      ElevatedButton(onPressed: (){
                        _controller.stop(); //停止
                      }, child:const Icon(Icons.refresh)),
                      ElevatedButton(onPressed: (){
                        _controller.reset(); //重置
                      }, child:const Icon(Icons.refresh)),
                    ]
                )
            )
        )
    );
  }
}

FadeTransition

RotationTransition实现透明度变化动画,opacity为AnimationController,可以在initState初始化的时候设置vsync,duration来让程序和手机的刷新频率统一,同时controller为0-1的值,因此opacity会发生从透明到实体的过程,如果要实现实体逐渐到透明可以使用reverse()倒序播放

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1));//让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              _controller.repeat(); //重复播放
            },child:const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: FadeTransition(opacity: _controller,
                child: const FlutterLogo(size: 60,),
              )
            )
        )
    );
  }
}

也可以通过lowerBound和upperBound来配置controller的最低和最高值

ScaleTransition

ScaleTransition实现放大缩小动画,scale为AnimationController,可以在initState初始化的时候设置vsync,duration来让程序和手机的刷新频率统一,同时controller为0-1的值,因此scale会发生从小到大的过程,如果要实现大逐渐到小可以使用reverse()倒序播放

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1));//让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              _controller.repeat(); //重复播放
            },child:const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
                child: ScaleTransition(scale: _controller,
                  child: const FlutterLogo(size: 60,),
                )
            )
        )
    );
  }
}

_controller.drive(Tween(begin:0.5,end: 1.5)), 即为开始时30 结束后为90 (初始为60)

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1),
          lowerBound: 0.5,
          upperBound: 1
        );//让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              _controller.repeat(); //重复播放
            },child:const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: ScaleTransition(scale: _controller.drive(Tween(begin:0.5,end: 1.5)),
                child: const FlutterLogo(size: 60,),
              )
            )
        )
    );
  }
}

SlideTransition

SlideTransition实现位移变化动画,position为AnimationController,可以在initState初始化的时候设置vsync,duration来让程序和手机的刷新频率统一,使用drive函数内部配置Tween()子组件Offset()设置初始位置和结束位置

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1),
            lowerBound: 0.5,
            upperBound: 1
        );//让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton:FloatingActionButton(onPressed: (){
              _controller.repeat(); //重复播放
            },child:const Icon(Icons.add),) ,
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
                child: SlideTransition(position: _controller.drive(Tween(begin: const Offset(0, 0),end: const Offset(1, 1))),
                  child: const FlutterLogo(size: 60,),
                )
            )
        )
    );
  }

配置曲线

chain函数内部使用CurveTween组件,同时可以继续使用链式操作继续配置动画

child: SlideTransition(position: Tween(begin: const Offset(0, 0),end: const Offset(0,2)).chain(CurveTween(curve: Curves.linear)).animate(_controller),

3.交错式动画

通过配置controller.drive()方法来配置交错动画

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  bool flag = false;
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this, duration: const Duration(seconds: 1, milliseconds: 1),
      // lowerBound: 0.5,
      // upperBound: 1
    ); //让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                flag? _controller.forward() : _controller.reverse();
                flag = !flag;
              },
              child: const Icon(Icons.add),
            ),
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
                child: Stack(
              children: [
                //实现交错式动画
                ScaleTransition(
                    scale: _controller.drive(Tween(begin: 0.0, end: 1.0)
                        .chain(CurveTween(curve: const Interval(0.5, 1)))),
                    child: const Icon(Icons.search)),
                ScaleTransition(
                  scale: _controller.drive(Tween(begin: 1.0, end: 0.0)
                      .chain(CurveTween(curve: const Interval(0, 0.5)))),
                  child: const Icon(Icons.close),
                )
              ],
            ))));
  }
}

交错动画实现方块位移

class _HomeState extends State<HomeState> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  bool flag = false;
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this, duration: const Duration(seconds: 1, milliseconds: 1),
      // lowerBound: 0.5,
      // upperBound: 1
    ); //让程序和手机的刷新频率统一
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                flag? _controller.forward() : _controller.reverse();
                flag = !flag;
              },
              child: const Icon(Icons.add),
            ),
            appBar: AppBar(
              title: const Text("测试"),
            ),
            body: Center(
              child: Column(
                children: [
                  //实现交错式动画
                  SlideTransition(position: _controller.drive(Tween(begin: const Offset(0.0, 0.0),end: const Offset(1.5, 0)).chain(CurveTween(curve: Curves.ease)).chain(CurveTween(curve: const Interval(0, 0.2)))),
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.blue[100],
                    ),
                  ),
                  SlideTransition(position: _controller.drive(Tween(begin: const Offset(0.0, 0.0),end: const Offset(1.5, 0)).chain(CurveTween(curve: Curves.ease)).chain(CurveTween(curve: const Interval(0.2, 0.4)))),
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.blue[300],
                    ),
                  ),
                  SlideTransition(position: _controller.drive(Tween(begin: const Offset(0.0, 0.0),end: const Offset(1.5, 0)).chain(CurveTween(curve: Curves.ease)).chain(CurveTween(curve: const Interval(0.4, 0.6)))),
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.blue[600],
                    ),
                  ),
                  SlideTransition(position: _controller.drive(Tween(begin: const Offset(0.0, 0.0),end: const Offset(1.5, 0)).chain(CurveTween(curve: Curves.ease)).chain(CurveTween(curve: const Interval(0.6, 0.8)))),
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.blue[900],
                    ),
                  ),
                ],
              ),
            )
        ));
  }

4.Hero动画

在路由组件内配置

class _HomeState extends State<HomeState>{

  Map routes = {
    "/" : (context) => const MyHomePage(),
    "/news" : (context, {arguments}) =>  NewsPage(arguments: arguments),
    "/setting" : (context, {arguments}) => SettingPage(arguments: arguments),
    "/page" :(context) => const MyPageView()
  };
    
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      onGenerateRoute: (RouteSettings settings){
        final String? name = settings.name;
        final Function? builder = routes[name];
        if (builder != null){
          if (settings.arguments != null){
            final Route route = CupertinoPageRoute(
                builder: (context) => builder(context,arguments:settings.arguments)
            );
            return route;
          }else{
            final Route route = CupertinoPageRoute(
                builder: (context) => builder(context)
            );
            return route;
          }
        }
        return null;
      },
      title: "richu",
      initialRoute: "/",
      home: RouteState(),
    );
  }
}

class RouteState extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: ListView(
            children: [
              ElevatedButton(onPressed: (){
                Navigator.pushNamed(context, "/news",arguments: {
                  "title":"组件news",
                  "aid":20
                });
              }, child: const Hero(tag: "组件news", child:Text("text"))),  //通过tag传递参数,类似android的子组件共享参数
            ],
          )
      ),
    );
  }
}

在子路由组件中使用hero组件接收参数

class _NewsPage extends State<NewsPage>{
      return ListView(
        children: [Hero(tag:widget.arguments["title"], child:Text(widget.arguments["title"])),ElevatedButton(onPressed: (){
          Navigator.of(context).pushReplacementNamed("/");
          //Navigator.of(context).pushAndRemoveUntil(newRoute, predicate);
        }, child: const Text("注册")),const SizedBox(height: 20,),ElevatedButton(onPressed: (){
            _alertDialog();
        }, child: const Text("取消")),const SizedBox(height: 20,),ElevatedButton(onPressed: (){
          _simpleDialog();
        }, child: const Text("提示信息")),const SizedBox(height: 20,),ElevatedButton(onPressed: (){
          _modelDialog();
        }, child: const Text("显示")),const SizedBox(height: 20,),ElevatedButton(onPressed: (){
          _mydialog();
        }, child: const Text("提示"))],
      );
  }
}

13.Getx

1.基本使用

1.状态管理

GetX 高性能的状态管理,智能的依赖注入和便捷的路由管理

get: ^4.6.1

flutter pub get

Get.defaultDialog(
    title: "提示信息",
    middleText: "确定删除?",
    confirm: ElevatedButton(onPressed: (){
        print("ok");
    }, child: const Text("确定")),
    cancel: ElevatedButton(onPressed: (){
        print("test");
    }, child: const Text("确定"))
);

返回上一级

Get.back();

2.组件的使用

初始化

class HomeState extends StatelessWidget{
  const HomeState({super.key});
  @override
  Widget build(BuildContext context) {

    return GetMaterialApp(
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.light,
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text("data"),
        ),
        body: const PageGet(),
      ),
    );
  }
}

defaultDialog

@override
Widget build(BuildContext context) {
    return Center(
        child: ElevatedButton(
            onPressed: () {
                Get.defaultDialog(
                    title: "提示信息",
                    middleText: "确定删除?",
                    confirm: ElevatedButton(onPressed: (){
                        Get.back();
                    }, child: const Text("确定")),
                    cancel: ElevatedButton(onPressed: (){
                        Get.back();
                    }, child: const Text("取消"))
                );
            },
            child: const Text("Show Dialog"),
        ),
    );
}

snackbar 默认在顶部

Get.snackbar("警告", "未知错误");
//配置位置
Get.snackbar("警告", "未知错误",snackPosition: SnackPosition.BOTTOM);

bottomSheet

Get.bottomSheet(Container(
    color: Colors.white,
    height: 200,
    child: Column(
        children: [
            ElevatedButton(onPressed: (){}, child: const ListTile(
                leading: Icon(Icons.sunny),
                title: Text("白天模式",style: TextStyle(color: Colors.black),),
            ),),
            ElevatedButton(onPressed: (){}, child:const  ListTile(
                leading: Icon(Icons.nightlight),
                title: Text("黑夜模式" ,style: TextStyle(color: Colors.black),),
            ))
        ],
    ),
));

3.通过getx切换主题

Get.bottomSheet(Container(
    color: Colors.white,
    height: 200,
    child: Column(
        children: [
            ListTile(
                leading: Icon(Icons.sunny),
                onTap: (){
                    Get.changeTheme(ThemeData.light());
                    Get.back();
                },
                title: const Text("白天模式",style: TextStyle(color: Colors.black),),
            ),
            ListTile(
                leading: Icon(Icons.nightlight),
                onTap: (){
                    Get.changeTheme(ThemeData.dark());
                    Get.back();
                },
                title:const Text("黑夜模式" ,style: TextStyle(color: Colors.black),),
            )
        ],
    ),
));

app

class HomeState extends StatelessWidget{
  const HomeState({super.key});
  @override
  Widget build(BuildContext context) {

    return GetMaterialApp(
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.light,
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text("data"),
        ),
        body: const PageGet(),
      ),
    );
  }
}

4.GetX进行路由切换

配置默认的路由切换动画

initialRoute: "/",
defaultTransition: Transition.rightToLeft,

Get.toNamed(“/login”) 去到指定路由

Get.offAll(const Tabs(index:4)) 去到根路径

Get.off(NextScreen()); 进入下一个页面但是没有返回按钮

Get.back() 返回

5.Getx配置路由

配置路由,参数可在组件内获取

rightToLeft来配置动画效果

class HomeState extends StatelessWidget {
  const HomeState({super.key});
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.light,
      debugShowCheckedModeBanner: false,
      initialRoute: "/",
      getPages: [
        GetPage(name: "/home", page: () => const MyHomePage()),
        GetPage(
            name: "/user",
            page: () => const UserPage(),
            transition: Transition.rightToLeft)
      ],
      home: Scaffold(
        appBar: AppBar(
          title: const Text("data"),
        ),
        body: const PageGet(),
      ),
    );
  }
}

传递参数

Get.toNamed("/news",arguments: {"title":"richu"});

接收参数

Get.arguments["title"], child: Text(Get.arguments["title"]

6.中间件

定义中间件

class ShopMiddleware extends GetMiddleware{
  RouteSettings? redirect(String? route){
      //return null 默认不做操作
    return null;
      //路由跳转,并且传递参数,如果没有参数可以传递空map
    return const RouteSettings(name: "/",arguments: {});
  }
}

配置中间件

GetPage(
    name: "/user",
    page: () => const UserPage(),
    transition: Transition.rightToLeft,
    middlewares: [
        ShopMiddleware()
    ]
),

配置多个中间件,并且配置优先级

ShopMiddleware(priority: 2)
class ShopMiddleware extends GetMiddleware{

  ShopMiddleware({super.priority});

  RouteSettings? redirect(String? route){
    //return null;
    return const RouteSettings(name: "/",arguments: {});
  }
}

2.状态管理

定义一个响应式变量

RxInt _counter = 0.obs;
RxString _name = "".obs;

监听

children: [Obx(()=>Text("$_counter.value"))],
Obx(()=>Text(_name.value))

定义响应式变量的方法

Rx<String> _test1 = Rx<String>("test");
RxString _test2 = RxString("test");

3.响应式状态管理

多个页面共享数据

//定义controller
import 'package:get/get.dart';

class CounterController extends GetxController{
  RxInt counter = 0.obs;

  inc(){
    counter++;
    update();
  }
  dec(){
    counter--;
    update();
  }
}
class _PageGet extends State<PageGet> {
  CounterController counterController = Get.put(CounterController());

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Obx(() => Text("${counterController.counter}")),
        ElevatedButton(
            onPressed: () {
              counterController.inc();
            },
            child: const Text("++")),
        ElevatedButton(
            onPressed: () {
              Get.toNamed("/news", arguments: {"title": "richu"});
            },
            child: const Text("to news"))
      ],
    );
  }
}

获取

CounterController counterController = Get.find();

ElevatedButton(onPressed: (){
    counterController.inc();
}, child:const Text("++")),
Obx(()=>Text("${counterController.counter}"))

2.Binding

import 'package:get/get.dart';
import 'package:richu/controllers/counter.dart';

class AllControllerBinding extends Bindings{
  @override
  void dependencies() {
    Get.lazyPut<CounterController>(()=>CounterController());
  }
}
return GetMaterialApp(
    theme: ThemeData.light(),
    darkTheme: ThemeData.dark(),
    themeMode: ThemeMode.light,
    debugShowCheckedModeBanner: false,
    initialRoute: "/",
    defaultTransition: Transition.rightToLeft,
    initialBinding: AllControllerBinding(),
    getPages: [
        GetPage(
            name: "/home",
            page: () => const MyHomePage(),
            transition: Transition.rightToLeft),
        GetPage(
            name: "/user",
            page: () => const UserPage(),
            transition: Transition.rightToLeft,
            middlewares: [ShopMiddleware(priority: 2)]),
        GetPage(
            name: "/news",
            page: () => const NewsPage(),
            transition: Transition.rightToLeft)
    ],
    home: Scaffold(
        appBar: AppBar(
            title: const Text("data"),
        ),
        body: const PageGet(),
    ),
);

配置之后无序put

4.使用GetView

import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import 'package:richu/controllers/counter.dart';

class CounterPage extends GetView<CounterController>{
  
  const CounterPage({super.key});
  
  @override
  Widget build(BuildContext context) {
      Get.put(CounterController());
      return Scaffold(
        appBar: AppBar(
          title: const Text("title"),
        ),
        body: Center(
          child: Column(
            children: [
              Obx(()=>Text("${controller.counter}")),
              const SizedBox(height: 20,),
              ElevatedButton(onPressed: (){
                controller.inc();
              }, child: const Text("++"))
            ],
          ),
        ),
      );
  }
}

在路由注入controller

GetPage(name: "/counter", page: () => const CounterPage(),binding:Counterbinding())

初始化后可以直接使用,无需put

5.controller的生命周期

@override
void onInit() {
    print("init");
}

@override
void onReady() {
    print("ready");
}

@override
void onClose() {
    print("close");
}

6.Flutter实现多语言配置

ElevatedButton(onPressed: () {}, child: const Text("切换到中文")),
const SizedBox(
    height: 20,
),
ElevatedButton(onPressed: () {}, child: const Text("切换到英文"))

定义语言

import 'package:get/get.dart';

class Message extends Translations {
  @override
  Map<String, Map<String, String>> get keys =>{
      'zh_CN':{
        'hello':"你好"
      },
      'en-US':{
        'hello':"hello richu"
      }
  };
}
return GetMaterialApp(
    theme: ThemeData.light(),
    darkTheme: ThemeData.dark(),
    themeMode: ThemeMode.light,
    debugShowCheckedModeBanner: false,
    initialRoute: "/",
    translations: Message(),
    locale: const Locale('zh','CN'), //指定默认的语言
    fallbackLocale: const Locale('en','US'), //添加一个回调语言选项
    defaultTransition: Transition.rightToLeft,
    }

切换语言

ElevatedButton(onPressed: () {
          var locale = const Locale("zh",'CN');
          Get.updateLocale(locale);
        }, child: const Text("切换到中文")),
        const SizedBox(
          height: 20,
        ),
        ElevatedButton(onPressed: () {
          var locale = const Locale("en",'US');
          Get.updateLocale(locale);
        }, child: const Text("切换到英文")),

7.GetUtils工具库

GetUtilsgetx为我们提供一些常用的工具类库,包括值是否为空是否是数字是否是视频、图片、音频、PPT、Word、APK邮箱、手机号码、日期、MD5、SHA1等等。

验证邮箱

class _PageGet extends State<PageGet> {
  TextEditingController textEditingController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
          TextField(
            controller: textEditingController,
          ),
        ElevatedButton(onPressed: (){
          if (GetUtils.isEmail(textEditingController.text)){
            Get.snackbar("正确", "验证成功");
          }else{
            Get.snackbar("错误", "错误的邮箱",colorText: Colors.red[100]);
          }
        }, child: const Text("验证邮箱"))
      ],
    );
  }
}

验证手机号

TextField(
    controller: textEditingController,
),
ElevatedButton(onPressed: (){
    if (GetUtils.isPhoneNumber(textEditingController.text) && textEditingController.text.length == 11){
        Get.snackbar("正确", "验证成功");
    }else{
        Get.snackbar("错误", "错误的手机号",colorText: Colors.red[100]);
    }
}, child: const Text("验证手机号")),