Flutter高频知识点梳理

一、小技巧

1、不占空间的空组件

SizedBox.shrink()

2、组件是否显示 - if

if (provider.pageState == DataStatus.completed) BottomMenuWidget(),

3、私有变量以下划线开头

Dart没有public,protected,private关键字,私有变量以下划线开头

未初始化的变量的初始值为null,即使数字类型的初始值也是null,因为在Dart中, everything is object!

dart的类实现call()方法可以像函数一样被调用

class WannabeFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

main() {
  var wf = new WannabeFunction();
  var out = wf("Hi","there,","gang");
  print('$out'); // Hi there, gang!
  print(wf.runtimeType); // WannabeFunction
  print(out.runtimeType); // String
  print(wf is Function); // false
}

4、Flutter页面重叠写法

1、叠加布局

Stack(
  children: [
    Positioned(
      top: -10,
      child: Container(
        // Container的其他属性和子组件
      ),
    ),
  ],
)

2、Transform.translate组件来进行位移调整

Transform.translate(
  offset: Offset(0, -10),
  child: Container(
    // Container的其他属性和子组件
  ),
)

3、Transform组件来应用变换矩阵来实现位移调整

Transform(
  transform: Matrix4.translationValues(0.0, -10.0, 0.0),
  child: Container(
    // Container的其他属性和子组件
  ),
)

二、核心语法

1、闭包语法

main(){
  List ls = ['aa','bb',3];
  List ls2 = ['dongnao simon',true,123];
//闭包
  Function weGame(List ls,func(a)){
    for(int i=0;i<ls.length;i++){
      ls[i] = func(ls[i]);
    }
    return (ls2)=>ls2+ls;
  }
  var weGame2 = weGame(ls, (a) =>a*2);
  print(weGame2(ls2));
}

weGame2(ls2)相当于 weGame(ls, (a) =>a*2)(ls2)

闭包好处防止变量污染

2、函数别名:类似java的抽象类

参考

typedef MyOperator(int a, int b);
// 1.List转String
var list=<String>['a','b'];
String str=JsonEncoder().convert(list);
print(str);

// 2.String转回List
List<String>list1=<String>[];
for(var value in JsonDecoder().convert(str)){
  print(value);
  list1.add(value);
};
list1.forEach(print);

3、mixins实现多继承

class D extends Person with A, B {
  D(String name, num age) : super(name, age);
}

在 Dart 中本不可以实现多继承,利用 mixins 可实现类似多继承的功能。

  • 作为 mixins 的类只能继承自 Object,不能继承其他类。
  • 作为 mixins 的类不能有构造函数。
  • 一个类可以 mixins 多个 mixins 类。
  • mixins 绝不是继承,也不是接口,而是一种全新的特性。

示例:

class A {
  String info = "this is A";

  void printA() {
    print("A");
  }

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

class B {
  void printB() {
    print("B");
  }

  void run() {
    print("B Run");
  }
}

class Person {
  String name;
  num age;

  Person(this.name, this.age);

  printInfo() {
    print('${this.name}----${this.age}');
  }

  void run() {
    print("Person Run");
  }
}

// 使用 with 关键字实现 mixins
class C with A, B {}

// 既继承自 Person 又 mixins A 和 B,with 后跟的类有顺序之分,后类的方法会覆盖前类的方法
class D extends Person with A, B {
  D(String name, num age) : super(name, age);
}

void main() {
  var c = new C();
  c.printA(); // A
  c.printB(); // B
  print(c.info); // this is A

  var d = new D('张三', 20);
  d.printInfo(); // 张三----20
  d.run(); // B Run
}

4、final 和 const

如果不希望变量被修改,可以使用 final 和 const 定义变量。

final 和 const 的区别就是在编译的时候 const 变量的值就是已经确定的,final不一定,可能需要运行的时候才能确定值。

final name = 'Bob';
const bar = 1000000;

5、算数除法( / 与 ~/)

print(5 / 2 == 2.5); // 结果是双浮点型
print(5 ~/ 2 == 2); // 结果是整型

6、库

1、自定义库

第1步:声明库

library library_name  

第2步:关联库

import 'library_name'
2、库前缀(区分同名库)

如果导入两个存在冲突标识符的库, 则可以为这两个库,或者其中一个指定前缀。

首先,定义一个库:loggerlib.dart,代码如下所示:

library loggerlib;  
void log(msg){ 
   print("Log method called in loggerlib msg:$msg");
}

接下来,将定义另一个库:webloggerlib.dart,代码如下所示:

library webloggerlib; 
void log(msg){ 
   print("Log method called in webloggerlib msg:$msg"); 
}

最后,导入带有前缀的库。

import 'loggerlib.dart'; 
import 'webloggerlib.dart' as web;  

// prefix avoids function name clashes 
void main(){ 
   log("hello from loggerlib"); 
   web.log("hello from webloggerlib"); 
}
3、延迟加载库

Deferred loading (也称之为 lazy loading) 可以让应用在需要的时候再加载库。 下面是一些使用延迟加载库的场景:

  • 减少 APP 的启动时间。
  • 执行 A/B 测试,例如 尝试各种算法的 不同实现。
  • 加载很少使用的功能,例如可选的屏幕和对话框。

要延迟加载一个库,需要先使用 deferred as 来导入:

import 'package:greetings/hello.dart' deferred as hello;

当需要使用的时候,使用库标识符调用 loadLibrary() 函数来加载库:

Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

在一个库上你可以多次调用 loadLibrary() 函数。但是该库只是载入一次。

7、异步Future

1、基础用法(两种then、await)

类似js的Promise,可以使用then、await两种方式获取结果

  • 使用then获取结果

值得注意的是,这里捕获异常是catchError(区别于js的catch),完成是whenComplete(区别于js的finally)

Future.delayed(Duration(milliseconds: 1000)).then((value) {
  print("结果:$value");
}).catchError((error) {
  print('$error');
}).whenComplete(() {
  print('代码执行完成');
});
  • 使用await获取结果
try{
  var result=await Future.delayed(Duration(milliseconds: 1000));
}catch(e){
  
}finally{
  
}
2、延迟加载

Future封装了delayed延迟任务

Future.delayed(Duration(milliseconds: 1), () {

});
3、async、await异步等待

异步等待用法,与js的promise如出一辙

void _onRefresh() async {
  await Future.delayed(Duration(milliseconds: 1000));
  refreshInfo();
}
4、自定义Future

Future的return:相当于Promise的resolve

Future的throw Exception:相当于Promise的reject

// 模拟一个网络请求
Future<String> getNetworkData() {
  return Future<String>(() {
    sleep(Duration(seconds: 3));
    // throw Exception("我是错误信息");
    return "我是请求到的数据";
  });
}
5、链式调用

可以使用then多次获取异步结果,也可以使用catchError多次捕获异常

main(List<String> args) {
  print('start');

  Future(() {
    sleep(Duration(seconds: 3));
    // throw Exception("第一次异常");
    return '第1次网络请求的结果';
  }).then((result) {
    print('$result');
    sleep(Duration(seconds: 3));
    return '第2次网络请求的结果';
  }).then((result) {
    print('$result');
    sleep(Duration(seconds: 3));
    return '第3次网络请求的结果';
  }).then((result) {
    print('$result');
  }).catchError((error) {
    print(error);
  });

  print('end');
}

8、泛型

1、类的泛型

在类型安全上通常需要泛型支持, 它的好处不仅仅是保证代码的正常运行:

  • 正确指定泛型类型可以提高代码质量。
  • 使用泛型可以减少重复的代码。
class BusinessBaseClass<T> {
  void printStr(T str) {
    print(str);
  }
}

void main() {
  var temp = BusinessBaseClass<double>();
  temp.printStr(1); //1.0
}
2、抽象类的泛型

封装上使用广泛

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}
3、限制泛型类型

通过extends关键字可以限制泛型类型

class SomeBaseClass {}

class BusinessBaseClass<T extends SomeBaseClass> {}

使用时

class Extender extends SomeBaseClass {}

void main() {
  var temp = BusinessBaseClass<Extender>();
}
4、泛型函数

泛型也可使用在函数上,下面示例取列表中的第一个元素

T first<T>(List<T> ts) {
  T tmp = ts[0];
  return tmp;
}

三、工具类封装

1、节流、防抖

yaml文件的dependencies添加依赖

async: 2.8.2
import 'package:async/async.dart';

/**
 * @author zhanglei
 * @version 1.0
 * @created 2022/10/22
 * @title 防抖
 * @description
 * @changeRecord 2022/10/18 modify  by zhanglei
 */
class ActionUtil {
  static Map<String, CancelableOperation> timeout = {};

  // 防抖 所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
  // 应用场景: 用户输入间隔多久后没有输入时进行检查
  /**
   * @desc 函数防抖
   * @param func 函数
   * @param wait 延迟执行毫秒数
   * @param immediate true 表立即执行,false 表非立即执行
   */
  static debounce(
    Function func, {
    int wait = 500,
    bool immediate = true,
    String key = 'default',
  }) async {
    if (timeout[key] != null) {
      timeout[key]?.cancel();
    }
    if (immediate) {
      bool callNow = timeout[key] == null;
      timeout[key] = CancelableOperation.fromFuture(
        Future.delayed(Duration(milliseconds: wait)),
        onCancel: () => {},
      );
      if (callNow) func();

      await timeout[key]?.value;
      timeout.remove(key);
    } else {
      timeout[key] = CancelableOperation.fromFuture(
        Future.delayed(Duration(milliseconds: wait)),
        onCancel: () => print(''),
      );
      await timeout[key]?.value;
      func();
    }
  }

  // 节流  所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
  // 应用场景: 需要稀释执行效率的地方使用,例如懒加载的时候监听滚动条。
  /**
   * @desc 函数节流
   * @param func 函数
   * @param wait 延迟执行毫秒数
   * @param immediate true 表示立即执行,false 表示非立即执行
   */
  static int previous = 0;

  static throttle(
    Function func, {
    int wait = 100,
    immediate = false,
    String key = 'default',
  }) async {
    if (immediate) {
      int now = DateTime.now().millisecondsSinceEpoch;

      if (now - previous > wait) {
        func();
        previous = now;
      }
    } else {
      if (timeout[key] == null) {
        timeout[key] = CancelableOperation.fromFuture(
          Future.delayed(Duration(milliseconds: wait)),
          onCancel: () => print(''),
        );
        await timeout[key]?.value;
        timeout.remove(key);
        func();
      }
    }
  }
}

使用

ActionUtil.debounce((){

})

2、深浅拷贝

在Flutter中,List<Map<String, dynamic>>存在深浅拷贝问题,可以通过以下方式处理:

1、使用json.decode()和json.encode()进行深拷贝:

import 'dart:convert';

List<Map<String, dynamic>> originalList = [...];
List<Map<String, dynamic>> copiedList = json.decode(json.encode(originalList));

2、使用List.generate()进行深拷贝:

序列化与发序列化这种是最经典的深拷贝方式,但是如果Map中dynamic存在数字、字符串混在一起,可能会导致decode出来的都是字符串,此时可以考虑这种

List<Map<String, dynamic>> originalList = [...];
List<Map<String, dynamic>> copiedList = List.generate(originalList.length, (index) => {...originalList[index]});
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值