Flutter(学前必看)基础

目录

    • 所有Widget汇总
        • Flutter组件的分类
        • 组件类以及继承关系
  • Dart语法
    • 一、Hello Dart
      • 1.入口
      • 2.打印
    • 二、定义变量
      • var/dynamic/const/final
        • var
        • dynamic与Object
        • final 或 const
        • 空安全(null-safety)
    • 三、数据类型
      • 基本类型
      • 集合
        • list/set/map
    • 四、函数
      • 函数返回值
      • 可选参数
      • 函数作为参数、返回值
      • 匿名函数
    • 五、运算符
      • 除法、整除、取余
      • ??= 和 ?? 和 。。和?:
        • 类型判定运算符
        • 级联操作符(。。)
      • list、set、map的for循环
      • while 和 do-while
      • break和continue
    • 六、类
      • 构造方法
      • 枚举
      • 单例模式
      • setter和getter
      • 继承 extends
      • 抽象类 abstract
      • 隐式接口 implements
      • Mixin混入 mixin with
    • 七、泛型
      • Object类型 和 T泛型
      • 空安全 “?”和“!”
    • 八、库
      • 库的导入
      • 库的定义
    • 九、多线程
      • 异步
      • flutter Stream 和Future的区别?
      • 计算密集型任务
      • 十、Widget
        • 1. flutter StatefulWidget和StatelessWidget的区别?
        • 2. flutter StatefulWidget和StatelessWidget的应用场景?
      • 基础组件
        • Text(文本)相关
        • TextField(输入)相关
        • Button(按钮)相关
          • flutter TextButton、ElevatedButton 和 OutlinedButton 和 IconButton的区别?
  • 更多:

所有Widget汇总

Flutter组件的分类
1、基础组件
文本,Text
按钮,TextButton等
图片图标,Image、Icon
输入框 和 表单,TextField、Form
进度指示器,LinearProgressIndicator、CircularProgressIndicator
单选框和复选框,Switch、Checkbox

2、布局之容器组件
装饰,DecoratedBox、BoxDecoration等,如颜色、背景、边框、渐变、阴影等
复合容器,Container,它是结合align、padding、margin、box、变换等多种功能。
尺寸,主要是设置页面的宽高大小 或 宽高比例。
宽高SizedBox、AspectRatio、LimitedBox、FractionallySizedBox等;
限制类ConstrainedBox、BoxConstraints、UnconstrainedBox等
对齐,Align
居中,Center
填充,Padding
剪裁,ClipOval、ClipPath、ClipRect、ClipRRect等
变换(如旋转等),Transform
适配(如换行,即超出父组件边界约束),FittedBox

3、布局组件
线性布局,Row、Column
弹性布局,Flex、Expanded
流式布局(子元素自动换行),Wrap、Flow
层叠布局,Stack、Positioned

4、复合组件(滚动、列表等)
简单滚动列表(类似iOS的ScrollView),SingleChildScrollView
列表,ListView、AnimatedList
二维列表(类似iOS的CollectionView),GridView
自定义滚动列表,CustomScrollView、NestedScrollView
TabBar,TabBarView

5、交互组件
手势,GestureDetector、GestureRecognizer等相关类
动画,Animation、Curve、AnimationController、Tween、Ticker等相关类
组件类以及继承关系
一、组件基类
abstract class DiagnosticableTree with Diagnosticable
abstract class Widget extends DiagnosticableTree

二、普通组件
abstract class StatelessWidget extends Widget
abstract class StatefulWidget extends Widget

// 状态
abstract class State<T extends StatefulWidget> with Diagnosticable


三、布局组件
// 布局类基类
abstract class RenderObjectWidget extends Widget 

// 包含一个子Widget,如:ConstrainedBox、DecoratedBox等
abstract class SingleChildRenderObjectWidget extends RenderObjectWidget 
  通过属性child关联单个widget

// 包含多个子Widget,一般都有一个children参数,接受一个Widget数组。如Row、Column、Stack等
abstract class MultiChildRenderObjectWidget extends RenderObjectWidget 
  通过属性children关联多个widget。

// Widget树的叶子节点,用于没有子节点的widget,通常基础组件都属于这一类,如Image。
abstract class LeafRenderObjectWidget extends RenderObjectWidget 

// Widget代理
abstract class ProxyWidget extends Widget
abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget

// 弹性布局,flex
class Flex extends MultiChildRenderObjectWidget

class Flexible extends ParentDataWidget<FlexParentData>
class Expanded extends Flexible

// 线性布局
class Column extends Flex
class Row extends Flex

// 设置padding
class Padding extends SingleChildRenderObjectWidget
// SizedBox 设置宽高
class SizedBox extends SingleChildRenderObjectWidget
// Spacer 基于flex的空白,内部基于Expanded实现的,它只是Expanded的一个包装类
class Spacer extends StatelessWidget

// 流式布局
class Wrap extends MultiChildRenderObjectWidget
class Flow extends MultiChildRenderObjectWidget

// 层叠布局
class Stack extends MultiChildRenderObjectWidget
class Positioned extends ParentDataWidget<StackParentData>

// 对齐与相对定位
class Align extends SingleChildRenderObjectWidget
class Center extends Align

/* 容器类组件*/
// 填充
class Padding extends SingleChildRenderObjectWidget

// 尺寸大小限制
class ConstrainedBox extends SingleChildRenderObjectWidget
class SizedBox extends SingleChildRenderObjectWidget
class AspectRatio extends SingleChildRenderObjectWidget
class FractionallySizedBox extends SingleChildRenderObjectWidget
class LimitedBox extends SingleChildRenderObjectWidget

class UnconstrainedBox extends StatelessWidget

// 装饰类组件
class DecoratedBox extends SingleChildRenderObjectWidget
class BoxDecoration extends Decoration

// 组合类容器
class Container extends StatelessWidget


/* Material常用组件类 */
class Scaffold extends StatefulWidget

abstract class PreferredSizeWidget implements Widget
class AppBar extends StatefulWidget implements PreferredSizeWidget

class Drawer extends StatelessWidget
class FloatingActionButton extends StatelessWidget

class BottomNavigationBar extends StatefulWidget 
class BottomNavigationBarItem

Dart语法

一、Hello Dart

1.入口

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

class MyApp extends StatelessWidget {
  • void代表没有返回值
  • 定义字符串的时候,可以使用单引号或双引号
  • 每行语句必须使用分号结尾

2.打印

//使用字符串插值($或者${name}) 来打印包含变量的字符串
void main() {
  String name = "Alice";
  int age = 25;
  print("My name is $name and I am $age years old.");
}

二、定义变量

var/dynamic/const/final

var

Dart 中 var 变量一旦赋值,类型便会确定,则不能再改变其类型

var t = "hi world";
// 下面代码在dart中会报错,因为变量t的类型已经确定为String,
// 类型一旦确定后则不能再更改其类型。
t = 1000;
dynamic与Object

dynamic与Object声明的变量都可以赋值任意对象,且后期可以改变赋值的类型,不同的是dynamic声明的对象编译器会提供所有可能的组合,而Object声明的对象只能使用 Object 的属性与方法, 否则编译器会报错

dynamic a;
 Object b = "";
 main() {
   a = "";
   printLengths();
 }   

 printLengths() {
   // 正常
print(a.length);
   // 报错 The getter 'length' is not defined for the class 'Object'
   print(b.length);
 }
final 或 const

不可更改变量,使用 final 或 const,两者区别在于:const 变量是一个编译时常量(编译时直接替换为常量值),final变量在第一次使用时被初始化。被final或者const修饰的变量,变量类型可以省略

//可以省略String这个类型声明
final str = "hi world";
//final String str = "hi world"; 
const str1 = "hi world";
//const String str1 = "hi world";
空安全(null-safety)
int i = 8; //默认为不可空,必须在定义时初始化。
int? j; // 定义为可空类型,对于可空变量,我们在使用前必须判空。

// 如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,
// 表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错
late int k;
k=9;

三、数据类型

基本类型

int age = 12;
double price = 10.0;
String name = "张飞";
String name2 = '张飞';//单双引号没区别
//多行字符串
String name3 = '''
张飞
诸葛亮
廉颇
''';
bool sex = false;

集合

list/set/map
var nameList = ["张飞","关羽","刘备"];
List<String> nameList2 =["张飞","关羽","刘备"];
List<String> nameList3 = [];

var nameSet = {"张飞","关羽","刘备"};
Set<String> nameSet2 = {"张飞","关羽","刘备"};
Set<String> nameSet3 = {};

var map = {"name": "张飞", "height": 1.88};
Map<String, Object> map2 = {"name": "张飞", "height": 1.88};
Map<String, Object> map3 = {};

四、函数

函数返回值

//无返回值
void fun1(){
  
}
//有返回值
int fun2(){
  return 1;
}
//单行简写
int fun3()=>1;

//返回类型 void  和 int 也可以省略

可选参数

注意, 只有可选参数才可以有默认值, 必须参数不能有默认值

//命名可选参数: {param1, param2, ...}
//位置可选参数: [param1, param2, ...]
  
//命名可选参数
optionParamsFun1(String name, {int age = 10, double height = 1.8}) {
    print('$name,$age,$height');
}
//required 标识为必选参数
optionParamsFun2(String name, {int age = 10,required double height}{
  print('$name,$age,$height');

}
//调用
optionParamsFun1('yh');
optionParamsFun1('yh',age: 20);
optionParamsFun1('yh',age: 20,height: 1.88);
// yh,10,1.8
// yh,20,1.8
// yh,20,1.88

//位置可选参数
optionParamsFun1(String name, [int age = 10, double height = 1.8]) {
    print('$name,$age,$height');
}
optionParamsFun1('yh');
optionParamsFun1('yh', 20);
optionParamsFun1('yh', 20, 1.88);
// yh,10,1.8
// yh,20,1.8
// yh,20,1.88

函数作为参数、返回值

//调用
test(){
  getFunc();
  test2(foo("张飞"));
}

//1.定义一个函数
foo(String name) {
  print(name);
}
//2.将函数作为另一个函数的返回值
getFunc() {
  return foo;
}
//3.将函数作为另一个函数的参数
test2(Function func) {
  func("func");
}

匿名函数

void main3() {
  var numbers = [1, 2, 3, 4, 5];
  
  //遍历
  numbers.forEach((element) {
    print(element);
  });

  // 使用匿名函数对列表中的每个元素进行平方
  var squaredNumbers = numbers.map((number) => number * number);

  print(squaredNumbers.toList()); // 输出: [1, 4, 9, 16, 25]
}

五、运算符

除法、整除、取余

  var num = 7;
  print(num / 3);//除 2.3333
  print(num ~/ 3);//整除 2
  print(num % 3);//取余 1

??= 和 ?? 和 。。和?:

test1(){
//当变量不为null时使用变量,
  var name = 'lucy';
  name ??= 'sala';
  print(name);//lucy
//当变量为null时,后面的值将被赋值给变量
  var name2 = null;
  name2 ??= 'Toms';
  print(name2);//Toms

//如果a>10,b就等于a,否则b = 11
 int a = 5;
 int b = a>10?a:11;
}
//当变量不为null时使用变量,
  var name = 'lucy';
  print(name ?? 'sala');//lucy
//当变量为null时使用后面的值
  var name2 = null;
  print(name2 ?? 'Toms');//Toms
类型判定运算符

as 将对象强制转换为特定类型。
is 和 is! 判断变量是不是某种类型。

级联操作符(。。)
class Person {
  String name = 'Tom';
  void eat() {
  }
  void drink() {
  }
  void sleep() {
  }
}
//..可以连续访问方法和属性(类似返回值为Person)
void test2(){
  Person()..name..eat()..drink()..sleep();
}

list、set、map的for循环

void test2(){
  List<String> names = ['Alice', 'Bob', 'Charlie'];
  //普通遍历
  for (int i = 0; i < names.length; i++) {
    print(names[i]);
  }
  //forEach 遍历
  names.forEach((name) {
    print(name);
  });
  //遍历的同时转换为大写
  List<String> upperCaseNames = names.map((name) => name.toUpperCase()).toList();
  print(upperCaseNames);
  //in 遍历
  for (String name in names) {
    print(name);
  }



  Set<String> mySet = {'A', 'B', 'C'};
  for (var item in mySet) {
    print(item);
  }

  mySet.forEach((item) {
    print(item);
  });

  //转为list然后遍历
  List<String> myList = mySet.toList();
  for (var item in myList) {
    print(item);
  }



  Map<String, dynamic> myMap = {'key1': 'value1', 'key2': 'value2'};
  //遍历键值对
  for (var entry in myMap.entries) {
    print('${entry.key}: ${entry.value}');
  }
  //遍历键值对
  myMap.forEach((key, value) => print('$key: $value'));

  //遍历键
  myMap.keys.forEach((key) => print(key));

  //遍历值
  myMap.values.forEach((value) => print(value));

}

while 和 do-while

while :先检查条件,再执行

int i = 0;
while (i < 5) {
  print(i);
  i++;
}

do-while :先执行,再检查

int i = 0;
do {
  print(i);
  i++;
} while (i < 5);

break和continue

for循环中,我们可以使用"break"关键字来提前结束循环

for (int i = 0; i < 10; i++) {
  if (i == 5) {
    break;
  }
  print(i);
}

使用"continue"时,会跳过当前迭代的剩余代码,直接进入下一次迭代

for (int i = 0; i < 10; i++) {
  if (i % 2 != 0) {
    continue;
  }
  print(i);
}

六、类

void main(List<String> args) {
//实例化
  var p1 = Person();
  p1.eat();
}

class Person {
  String name = 'Tom';

  void eat() {
    String name = 'lucy';
    print(name);//lucy
    print(this.name);//Tom
  }
}

构造方法

Dart为类提供了默认的构造函数,当有了自己的构造函数,默认的构造方法将会失效,

在Flutter中,构造方法有几种方式:默认、命名、工厂、常量

默认构造方法:这是最常见的构造方法,它没有任何参数。例如:
复制代码

class MyClass {
  MyClass() {
    // 构造方法的逻辑
  }
}

命名构造方法:使用命名构造方法可以为类提供多个不同的构造方法,每个构造方法可以有不同的参数。例如:

class MyClass {
  MyClass() {
    // 默认构造方法
  }
  
  MyClass.namedConstructor() {
    // 命名构造方法
  }
}

在使用命名构造方法时,可以通过指定构造方法的名字来调用它。

带参数的构造方法

class MyClass {
  int value;
  
  MyClass(int value) {
    this.value = value;
  }
}

工厂构造方法:可以返回一个已经存在的实例,或者返回一个子类的实例。例如:

class MyClass {
  factory MyClass() {
    return _singleton;
  }
  
  MyClass._internal();
  
  static final MyClass _singleton = MyClass._internal();
}

在这个例子中,工厂构造方法返回一个单例实例。

常量构造方法,成员变量必须是final修饰,使用const关键字实例化

class Person {
  final String name;
  final int age;

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

枚举

void main(List<String> args) {
  print(Colors.red);
  //枚举属性 index索引,从0开始;values包含所有枚举值的list
  print(Colors.red.index);
  print(Colors.values);
}

enum Colors {
  red,
  green,
  blue
}

单例模式

//写法一
class Singleton {
  const Singleton._internal();
  factory Singleton() => const Singleton._internal();
}
Singleton single = Singleton();

//写法二
class Singleton {
  Singleton._privateInstance();
  static final Singleton instance = Singleton._privateInstance();
  factory Singleton(){
    return instance;
  }
}
//使用
Singleton single = Singleton();

//写法三
class Singleton {
  Singleton._internal();
  static final Singleton _instance = Singleton._internal();
  static Singleton getInstance() {
    return _instance;
  }
}
//使用
var instance = Singleton.getInstance();

//写法四
class Singleton {
	// 私有化构造方法
	Singleton._privateConstructor();
	static final Singleton _instance = Singleton._privateConstructor();
	//同下 : static Singleton get instance => _instance;
	static Singleton get instance { return _instance;}
}
//使用
var instance = Singleton.instance;

//写法五
class Singleton {
	Singleton._privateConstructor();
	static final Singleton instance = Singleton._privateConstructor();
}
//使用
void mian(){
	var instance = Singleton.instance;
    var instance2 = Singleton.instance;
    print(instance == instance2);
}

setter和getter

class Person {
  var name;

  set setName(String nameStr){
    name = nameStr;
  }

  String get getName{
    print('getName');
    return name;
  }
}

  Person p = Person();
  p.name = '123';
  print(p.getName);//getName  123

继承 extends

class Person {
  var name;

  Person(this.name);

  set setName(String nameStr){
    name = nameStr;
  }

  String get getName{
    print('getName');
    return name;
  }

  eat() {
  }

  run(){
    print('person run');
  }
}

class Student extends Person {
  int age;
  Student.withAge(String name, this.age): super(name);

  @override
  run() {
    // TODO: implement run
    super.run();
    print('student run');
  }
}

test(){
  Student s =  Student.withAge('Tom', 18);
  s.name = '123';
  print(s.getName);//getName  123
  s.run();
  //person run
// student run
}

抽象类 abstract

abstract class Animal {
  eat();
  run(){
  }
}

class Dog extends Animal {

  @override
  eat() {
    // TODO: implement eat
  }

}

class SmallDog extends Dog {
  @override
  run() {
    // TODO: implement run
  }
}

隐式接口 implements

Dart中的接口比较特殊, 没有一个专门的关键字来声明接口.
默认情况下,定义的每个类都相当于默认也声明了一个接口,可以由其他的类来实现(因为Dart不支持多继承)

 class Eat {
  eat() {
  }
}
abstract class Run {
  run() {

  }
}

class Animal implements Eat,Run {

  @override
  run() {
    // TODO: implement run
  }

  @override
  eat() {
    // TODO: implement eat
    throw UnimplementedError();
  }

}

Mixin混入 mixin with

除了通过class定义类,也可以通过mixin定义一个类。
通过mixin定义的类用于被其他类混入使用,通过with关键字来进行混入。

mixin Eat {
  eat();
}
mixin Run {
  run(){
  }
}

class Animal with Eat,Run {

  @override
  eat() {
    // TODO: implement eat
  }
  // @override
  // run() {
  //   // TODO: implement run
  // }

}

七、泛型

//泛型写法 
  // List
  //_InternalLinkedHashMap
  var list = ['a','b','c',123];
  var dic = {'key1':'value1', 'key2':123};
  //限制类型
  var list2 = <String>['a','b','c'];
  var dic2 = <String, String>{'key1':'value1', 'key2':'value2'};
 
  

Object类型 和 T泛型

//object
class Person {
  Object name;
  Object age;
  Person(this.name, this.age);
}

  Person p = Person('yh',18);
  print(p.name.runtimeType);
  print(p.age.runtimeType);

//T
class Person<T extends num> {
  T age;
  T height;
  Person(this.age, this.height);

  double sum(){
    double s = (this.age as int) * (this.height as double);
    return s;
  }
}

  Person p = Person(10,1.88);
  print(p.age.runtimeType);// int
  print(p.sum());// 18.799999999999997

空安全 “?”和“!”

//age可以为null
int? age = null;
  age = 10;
  //!表示age必然不为null
  double height = age! * 10.0;
  print(height);

八、库

库的导入

常见的库URI有三种不同的形式

来自dart标准版,比如dart:io、dart:html、dart:math、dart:core(但是这个可以省略)

//dart:前缀表示Dart的标准库,如dart:io、dart:html、dart:math
import 'dart:io';

使用相对路径导入的库,通常指自己项目中定义的其他dart文件

//当然,你也可以用相对路径或绝对路径的dart文件来引用
import 'lib/student/student.dart';

Pub包管理工具管理的一些库,包括自己的配置以及一些第三方的库,通常使用前缀package

//Pub包管理系统中有很多功能强大、实用的库,可以使用前缀 package:
import 'package:flutter/material.dart';

库文件中内容的显示和隐藏:
如果希望只导入库中某些内容,或者刻意隐藏库里面某些内容,可以使用show和hide关键字

//show关键字:可以显示某个成员(屏蔽其他)
//hide关键字:可以隐藏某个成员(显示其他)
import 'lib/student/student.dart' show Student, Person;
import 'lib/student/student.dart' hide Person;

当各个库有命名冲突的时候,可以使用as关键字来使用命名空间

//库中内容和当前文件中的名字冲突
import 'lib/student/student.dart' as Stu;
Stu.Student s = new Stu.Student();

库的定义

library关键字
通常在定义库时,我们可以使用library关键字给库起一个名字。

但目前我发现,库的名字并不影响导入,因为import语句用的是字符串URI

library math;

part关键字
在之前我们使用student.dart作为演练的时候,只是将该文件作为一个库。

在开发中,如果一个库文件太大,将所有内容保存到一个文件夹是不太合理的,我们有可能希望将这个库进行拆分,这个时候就可以使用part关键字了

不过官方已经不建议使用这种方式了:
mathUtils.dart文件

part of "utils.dart";

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

dateUtils.dart文件

part of "utils.dart";

String dateFormat(DateTime date) {
  return "2020-12-12";
}

utils.dart文件

part "mathUtils.dart";
part "dateUtils.dart";

test_libary.dart文件

import "lib/utils.dart";

main(List<String> args) {
  print(sum(10, 20));
  print(dateFormat(DateTime.now()));
}

export关键字
官方不推荐使用part关键字,那如果库非常大,如何进行管理呢?

将每一个dart文件作为库文件,使用export关键字在某个库文件中单独导入
mathUtils.dart文件

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

dateUtils.dart文件

String dateFormat(DateTime date) {
  return "2020-12-12";
}

utils.dart文件

library utils;

export "mathUtils.dart";
export "dateUtils.dart";

test_libary.dart文件

import "lib/utils.dart";

main(List<String> args) {
  print(sum(10, 20));
  print(dateFormat(DateTime.now()));
}

也可以通过Pub管理自己的库。

九、多线程

异步

1、使用async/await语法:使用async关键字定义一个异步函数,并在需要进行异步操作的地方使用await关键字来等待异步操作的结果。例如:

Future<int> fetchData() async {
  await Future.delayed(Duration(seconds: 1));
  return 42;
}

void main() async {
  print("Start");
  int result = await fetchData();
  print("Result: $result");
}

2、使用Future对象:可以使用Future对象来表示一个异步操作,并使用then方法来处理异步操作的结果。例如:

Future<int> fetchData() {
  return Future.delayed(Duration(seconds: 1), () => 42);
}

void main() {
  print("Start");
  fetchData().then((result) {
    print("Result: $result");
  });
}

whenComplete:Future 完成(无论是成功还是失败)后调用该回调函数

Future<int> fetchSomeData() async {
  // 模拟异步操作
  await Future.delayed(Duration(seconds: 2));
  
  // 返回一个成功的结果
  return 42;
}

void main() {
  fetchSomeData()
    .then((value) {
      print('成功获取到数据:$value');
    })
    .catchError((error) {
      print('获取数据时发生错误:$error');
    })
    .whenComplete(() {
      print('无论成功或失败,都会执行这个回调函数');
    });
}

fetchSomeData 函数模拟了一个异步操作,它会在2秒后返回一个成功的结果。在 main 函数中,我们使用 .then 方法注册了一个成功时的回调函数,并使用 .catchError 方法注册了一个失败时的回调函数。最后,我们使用 .whenComplete 方法注册了一个无论成功或失败都会执行的回调函数。

3.使用Stream对象:Stream是一种用于处理异步数据流的对象,可以通过添加监听器来处理异步操作的结果。例如:

Stream<int> fetchData() {
  return Stream.periodic(Duration(seconds: 1), (count) => count).take(3);
}

void main() {
  print("Start");
  fetchData().listen((result) {
    print("Result: $result");
  });
}

以上是Flutter中几种常见的实现异步操作的方式

flutter Stream 和Future的区别?

在Flutter中,Stream和Future是用于处理异步操作的两种不同的机制。

Future是一种表示异步操作结果的对象。它通常用于表示一次性的操作,例如从网络获取数据或执行耗时任务。当一个Future对象被创建时,它立即开始执行,并且可以通过await关键字来等待其结果。Future只能返回一个结果,并且一旦结果可用,它将不会再次改变。您可以通过使用.then()方法或async/await语法来处理Future的结果。

Stream是一种表示一系列异步操作结果的对象。它通常用于表示实时或连续的数据流,例如从数据库查询结果或用户输入事件。当一个Stream对象被创建时,它并不会立即开始执行,而是每当有新的数据可用时,会通过事件的形式传递给监听器。您可以使用StreamSubscription来监听Stream的事件,并对每个事件做出相应的处理。

因此,Future适用于一次性的异步操作,而Stream适用于连续的异步数据流。在使用时,您可以根据具体需求来选择使用Future还是Stream。

计算密集型任务

Flutter中的compute函数是一个用于在Isolate中执行计算密集型任务的函数。Isolate是Dart中的一个概念,它类似于线程,但是具有独立的内存空间,可以并行执行任务。

使用compute函数,可以将计算密集型的任务从主线程中分离出来,以避免阻塞UI线程,从而提高应用的性能和响应能力。

下面是compute函数的基本用法示例:

import 'dart:async';
import 'package:flutter/foundation.dart';

Future<int> calculate(int n) async {
  // 在这里执行计算密集型任务
  int result = 0;
  for (int i = 1; i <= n; i++) {
    result += i;
  }
  return result;
}

void main() async {
  // 使用compute函数在Isolate中执行计算任务
  int result = await compute(calculate, 1000000);
  print(result);
}

在上面的示例中,calculate函数是一个计算密集型的任务,它将对1到给定参数n之间的所有数字求和。main函数使用compute函数调用calculate函数,并传递一个参数1000000。compute函数会将calculate函数发送到一个新的Isolate中执行,并返回计算结果。

十、Widget

1. flutter StatefulWidget和StatelessWidget的区别?

StatefulWidget和StatelessWidget是Flutter中用于构建用户界面的两种基本组件类型。

StatefulWidget是有状态的组件,它依赖于一个状态对象(State)来管理和维护数据。当这个状态对象发生变化时,StatefulWidget会触发重新构建,从而更新界面。StatefulWidget适用于需要根据数据动态更新界面的场景,比如表单输入、计数器等。

StatelessWidget是无状态的组件,它不依赖于任何状态对象,一旦创建就不会再改变。StatelessWidget适用于静态内容的展示,比如文本、图像等。

选择使用StatefulWidget还是StatelessWidget取决于你的界面是否需要动态更新
如果界面的展示内容不随任何状态信息的变化而变化,可以选择使用StatelessWidget;
如果界面的展示内容需要根据数据动态更新,可以选择使用StatefulWidget。

2. flutter StatefulWidget和StatelessWidget的应用场景?

在实际使用中,应根据具体情况来选择适合的组件类型。如果界面只有一些静态内容,没有交互和状态变化,可以使用StatelessWidget;如果界面需要有交互和状态变化,可以使用StatefulWidget。

需要注意的是,过度使用StatefulWidget可能会影响应用的渲染性能。因为StatefulWidget的更新会触发整个界面的重新构建,包括所有子组件的销毁和重建。所以在选择组件类型时,需要综合考虑界面的动态性和性能需求。

总结来说,
StatefulWidget适用于需要根据数据动态更新界面的场景,
而StatelessWidget适用于静态内容的展示。
正确选择组件类型可以提高应用的性能和开发效率。

基础组件

Text(文本)相关
Text(
  'Hello, world!',
  style: TextStyle(
    fontSize: 20,
    color: Colors.blue,
  ),
)
//RichText是用来展示富文本的组件,它支持多种样式的文本混合在一起展示
RichText(
  text: TextSpan(
    text: 'Hello',
    style: TextStyle(color: Colors.black),
    children: <TextSpan>[
      TextSpan(
        text: 'world',
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
      TextSpan(
        text: '!',
        style: TextStyle(color: Colors.red),
      ),
    ],
  ),
)
//允许用户选择和复制文本内容
SelectableText(
  'Hello, World!',
  style: TextStyle(fontSize: 20),
)
TextField(输入)相关
TextField(
  decoration: InputDecoration(
    labelText: '请输入文本',
  ),
)
//与TextField类似,但提供了更多的验证和表单功能。
Form(
  child: TextFormField(
    decoration: InputDecoration(
      labelText: '请输入文本',
    ),
    validator: (value) {
      if (value.isEmpty) {
        return '请输入文本';
      }
      return null;
    },
  ),
)
//一个iOS风格的文本输入框控件
CupertinoTextField(
  placeholder: '请输入文本',
)
//SearchDelegate是Flutter中的一个抽象类,可以用来实现搜索功能。
//要使用SearchDelegate,需要先创建一个继承自SearchDelegate的子类,并实现一些必要的方法。
class CustomSearchDelegate extends SearchDelegate {
  @override
  List<Widget> buildActions(BuildContext context) {
    return [
      IconButton(
        icon: Icon(Icons.clear),
        onPressed: () {
          query = '';
        },
      ),
    ];
  }

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      icon: Icon(Icons.arrow_back),
      onPressed: () {
        close(context, null);
      },
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    // 在这里处理搜索结果的展示
    return Container();
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    // 在这里处理搜索建议的展示
    return Container();
  }
}

在buildActions方法中,我们可以添加一些操作按钮,比如清除搜索内容的按钮。buildLeading方法用于创建返回按钮。buildResults方法中可以展示搜索结果,buildSuggestions方法中可以展示搜索建议。

Button(按钮)相关
TextButton(
  onPressed: () => print('TextButton pressed'),
  child: Text('Btn'),
),
ElevatedButton(
  onPressed: () => print('ElevatedButton pressed'),
  child: Text('Btn'),
),
OutlinedButton(
  onPressed: () => print('OutlinedButton pressed'),
  child: Text('Btn'),
),
IconButton(
  onPressed: () => print('IconButton pressed'),
  icon: Icon(Icons.add),
)
flutter TextButton、ElevatedButton 和 OutlinedButton 和 IconButton的区别?

TextButton、ElevatedButton、OutlinedButton和IconButton是Flutter中的不同类型的按钮控件,它们在外观和功能上有一些区别。

TextButton(文本按钮):TextButton是一个扁平化的按钮,没有背景颜色,默认透明。点击时会出现墨水飞溅效果。TextButton通常用于需要较为简洁和清晰的界面设计。

ElevatedButton(凸起按钮):ElevatedButton是一个凸起的按钮,带有一个默认的背景颜色。点击时会有一个升起的动画效果。ElevatedButton通常用于需要突出显示的操作,比如提交表单或重要的用户交互。

OutlinedButton(轮廓按钮):OutlinedButton是一个带有边框的按钮,没有背景颜色,默认透明。点击时会出现墨水飞溅效果。OutlinedButton通常用于需要较为轻量级的操作,比如取消或返回。

IconButton(图标按钮):IconButton是一个只包含图标的按钮,没有文字内容。IconButton通常用于需要仅使用图标表示操作的场景。

更多:

Dart 方方面面,▩Dart-可迭代集合
Flutter:组件Widget
Flutter 布局详解十篇
dart 和 Flutter ,Flutter:第三方常用库整理

推荐:Flutter学习笔记(汇总)

你可能感兴趣的:(Flutter,flutter,flutter,基础必看)