flutter个人札记

基于同步或者异步的方法,创建异步执行的方法
Future<R> Function<Q, R>(FutureOr<R> Function(Q), Q, {String? debugLabel}) compute
Type: Future<R> Function<Q, R>(FutureOr<R> Function(Q), Q, {String? debugLabel})

package:flutter/src/foundation/isolates.dart

A function that spawns an isolate and runs the provided callback on that isolate, passes it the provided message, and (eventually) returns the value returned by callback.

This is useful for operations that take longer than a few milliseconds, and which would therefore risk skipping frames. For tasks that will only take a few milliseconds, consider [SchedulerBinding.scheduleTask] instead.

www.youtube.com/watch?v=5AxWC49ZMzs

调用
compute(func, argvs, )
本质是调用另一个方法
const ComputeImpl compute = isolates.compute;

 

 
Flutter中函数参数,使用 [] 包含的参数列表,代表可选参数;使用 {} 包含的参数列表,是给参数命名;这些参数都可以使用 = 进行赋值,但是参数名不应该以_开头
https://flutter.cn/docs/development/ui/layout/building-adaptive-apps
https://pub.dev/ 第三方组件地址
 

 

Flutter应用编译的时候会生成对应平台的动态库(打包进所有布局和业务逻辑),当程序开始运行时,取出FlutterViewController进行初始化,根视图就类似最顶端的 根Widget
Widget 类似于 CALayer/Layout (主要是布局,很多Widget是不带显示状态的,用来构建视图层级树)
State 应当与数据和视图的一个绑定关系 (每个State对象会返回一个Widget,通过setState()方法刷新Widget)
StateFulWidget 包含一个 State,是否可以有多个呢?如何切换? (所有可变的数据都是在State对象中,StateFulWidget相当于ViewController处理了数据和视图交互)
Widget是临时对象,用于构建当前状态下的应用程序,而State对象在多次调用build()之间保持不变,允许它们记住信息(状态)
在Flutter中,事件流是“向上”传递的,而状态流是“向下”传递,这类似于React/Vue中父子组件通信的方式:子widget到父widget是通过事件通信(通过子触发事件调用父的函数),而父到子是通过状态(父在build函数调用时初始化提供参数信息给到子)
在Flutter动画中AnimationController设置了动画的时间、循环次数,Animation设定了数值变化的线性情况、对应的数据变化范围情况,同时外部通过访问这个对象,可以获取当前的动画属性数值(将一个多个属性进行变化,触发变化后刷新widget)
https://flutterchina.club/tutorials/animation/#animationdouble 描述了很多实现动画的方法,最后推荐的是AnimatedBuilder这种方法,它是继承自AnimatedWidget的(从名字看就是一个显示动画效果的Widget)
https://www.flutterhub.cn 可以用作学习的flutter项目/代码
https://blog.csdn.net/u010126792/article/details/82347269 yaml依赖/配置文件说明
flutter pub get 在项目目录下使用这个命令去更新依赖的库
flutter命令找不到时,通过下面方法将之前下载好的flutter指令所在bin目录加入到PATH变量中
Mac系统的环境变量,加载顺序为:
/etc/profile /etc/paths ~/.bash_profile ~/.bash_login ~/.profile ~/.bashrc
当然/etc/profile和/etc/paths是系统级别的,系统启动就会加载,后面几个是当前用户级的环境变量。后面3个按照从前往后的顺序读取,如果~/.bash_profile文件存在,则后面的几个文件就会被忽略不读了,如果~/.bash_profile文件不存在,才会以此类推读取后面的文件。~/.bashrc没有上述规则,它是bash shell打开的时候载入的。修改环境变量也即是修改上面几个文件,我选择修改最后一个,一般控制台输入: export PATH=<path>:$PATH  其实意思就是将PATH环境变量修改为新增的PATH加上原来的PATH(多个PATH之间使用:隔开)填入<path>时可以使用`pwd`代表当前的工作目录
如果在VS Code中打开了控制台,那么除了使用 source ~/.bashrc使得环境变量立即生效外,如果又是在其他的控制台进行的操作,那么就需要在VS Code中重新开一个终端
Expanded Widget会拥有父级容器剩余的空间
https://flutterchina.club/tutorials/layout/  布局的学习
https://book.flutterchina.club/#缘起  电子书查看
Stack 用来实现重叠的布局 (alignment设定重叠的位置,第一个子Widget是底层的视图,后续依次往上叠,一般而言最下层的视图最大所以是以最下层的为基准做重叠)
Stack 加上 Positioned 可以实现所有的重叠布局(flutter计算布局还是很智能,写下去基本就是自己想要的效果,Positioned可以设定上左下右的间距)
flutter的一个问题时,程序员基本上要控制完整的层级树,一个其他语言比较容易实现的控件/布局,需要写上一大堆Widget(如果进行一些封装会好好多,如果有第三方就最好啦)
flutter获取屏幕的宽高(尺寸,不是物理屏幕分辨率),通过 MaterialApp 的 home Widget 的 build 方法中 (如果是StatefulWidget则是在State的 build 方法中),调用 Size screenSize = MediaQuery.of(context).size; 获取到屏幕的宽高(根视图的大小),并且可以将这个值一直传递下去(更好的方式是通过一个环境配置类的静态变量,一次赋值,多处使用)。
flutter可以选择运行设备,在VS Code底部的橙色栏目中,右边有显示运行的设备,可以点击选择想要运行的设备。
ListView相当于UIScrollView,但是ListView.Builder()方法创建出来的ListView就更像是UITableView了
flutter可以和原生通信,有点和weex与原生通信,整个结果返回是异步进行的。实践中使用的方法是通过 MethodChannel,一般来说建立一个 MethodChannel 就足够了,可以在原生中通过参数对消息进行分发到各个辅助模块去处理,flutter中可以封装不同的调用方法,安排到不同的类对象。
import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let messageChannel = FlutterMethodChannel(name: "common.flutter.app/message",
                                                  binaryMessenger: controller.binaryMessenger)
    messageChannel.setMethodCallHandler({
      (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
      // Note: this method is invoked on the UI thread.
        let name = call.method;
        let args = call.arguments;
        result(AppDelegate.execCall(name: name, args: args as AnyObject?));
    })
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    static func execCall(name : String, args : AnyObject?) -> AnyObject? {
        switch name {
            case "imagePath": do {
                let param = args as! Dictionary<String, Any>;
                let icon = param["icon"] as! String;
                print("\n\(Bundle.main.bundlePath)\n需要获取的图片名称为 \(icon)", "\n");
                let path = Bundle.main.path(forResource: icon, ofType: "png") ?? "";
                print("取得的地址为 \(path)")
                return path as AnyObject;
            }
            default: do {
                return nil;
            }
        }
    }
}
void requestImagePath() async {
    try {
      String path = await EnvUntils.platformCaller
          .invokeMethod('imagePath', {'icon': 'AppIcon60x60@3x'});
      setState(() {
        imagePath = path;
      });
    } catch (e) {}
  }

 

Image这个Widgwt可以多种类型的图片,具体通过制定其中的image数据源属性,可以是NetworkImage对象 初始化参数传入图片地址 FileImage对象初始化参数传入文件对象(由文件地址进行初始化)等其他

原生调用flutter
void main() {
  EnvUntils.platformCaller = MethodChannel('common.flutter.app/message');
  EnvUntils.platformCaller
      .setMethodCallHandler((call) => receivedNativeMethod(call));
  runApp(MyApp());
}

Future<dynamic> receivedNativeMethod(MethodCall methodCall) async {
  String method = methodCall.method;
  if (method == 'pageContent') {
    
  }
  return '';
}

 

原生如何使用指令跳转到指定的Flutter页面

1.假设每次触发只会去打开一个Flutter页面

2.原生调用Flutter方法,存储一个页面的标记和页面参数,通过参数实例化不同的页面 (或者Flutter页面一开始创建为空,然后主动去请求标记和参数,获得后重新刷新页面)

3.实例化Flutter页面的时候存储这个标记,并且保持原生和Flutter端标记一致,在Flutter中将State对象存入到一个静态的数组中,在收到消息时,在静态数组中找到对应的State,进而确定对应的App页面

 
附带flutter项目一份 https://files.cnblogs.com/files/yuxiaoyiyou/simple_example.zip
posted @ 2021-04-27 09:41  雨筱逸悠  阅读(98)  评论(0编辑  收藏  举报