flutter个人札记

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("
(Bundle.main.bundlePath)
需要获取的图片名称为 (icon)", "
");
                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
原文地址:https://www.cnblogs.com/yuxiaoyiyou/p/14707593.html