Flutter 从零到一

814 阅读3分钟

iOS 调试

真机调试

  1. Xcode run 在控制台获取 Dart VM service URI

  2. VSCode 点击 Cmd + Shift + P 选择 Debug: Attach to Flutter on Device

  3. 粘贴 the URI 后点击 Enter image.png 官方文档: 在混合开发模式下进行调试

常见问题:Exception attempting to connect to the VM Service: SocketException: Connection refused

flutter devices
flutter attach -d <deviceId>

inspector

  1. VSCode 点击 Cmd + Shift + P 选择 Dart: Open DevTools in Browser
  2. select widget mode image.png

通用地图

状态管理

Consumer

  • 监听Provider提供的数据,当在应用的某个地方使用Provider 来暴露一个数据模型时,你可以在widget树的任何其他地方使用 Consumer 来读取并响应这个数据模型的变化。
  • 当 Provider 中的数据发生变化时,Consumer 会自动重建其子widget,这样就可以根据新的数据状态更新UI。

Provider 数据更新后页面未刷新

  1. 没有调用 notifyListeners()
  2. context 不同 页面若取的是当前页面的 context 而不是管理 Provider 数据页面的 context 那无法拿到 Provider 数据
  3. 没有触发 set 方法 在方法中更新私有变量时直接调用的下划线方法 _unreadNum 而不是通过它的 setter 方法来更新的
  4. 没有改变引用
    • Selector 监听的是 messageList 的引用变化。如果只是对列表进行操作,如 add 而不更新列表的引用,Selector 不会检测到变化。
    • 直接赋值,例如 List<MessageDetailModel?> newMessageList = messageList; 赋值没有真正改变其值,在这种情况下,shouldRebuild 函数会返回 false。应该使用 List<MessageDetailModel?> newMessageList = List.from(messageList);

异步

Group

Future<void>? _sendInfoFuture;
Future<void>? _receiptInfoFuture;

@override
void onSuccessCallBack(BaseResponse? response, String tag) {
if (tag == xxx) {
   _sendInfoFuture = Future.value();
} else if (tag == xxx) {
   _receiptInfoFuture = Future.value();
}

// 优化请求都成功后再更新数据
if (_sendInfoFuture != null && _receiptInfoFuture != null) {
   Future.wait([_sendInfoFuture!, _receiptInfoFuture!]).then((_) {
     changeCount(sendNumber: sendList?.packageNum, receiveNumber: receiveList?.packageNum);
     notifyListeners();
   });
  }
}

原生交互

// 原生代码   
FlutterMethodChannel *pushInitChannel = [FlutterMethodChannel methodChannelWithName:@"jd.logistic.pushInitChannel" binaryMessenger:controller.binaryMessenger];
[pushInitChannel invokeMethod:@"saveNotification" arguments:jsonString];
    
  
// flutter 代码
MethodChannel pushInitChannel = MethodChannel('jd.logistic.pushInitChannel');
pushInitChannel.setMethodCallHandler(_handleNativeMethod);

Future<void> _handleNativeMethod(MethodCall call) async {
    switch (call.method) {
      case 'saveNotification':
        String data = call.arguments;
        saveMessageToDatabase(data);
        break;
      default:
        print("Unknown method called");
    }
  }

国际化

VSCode 安装 flutter Intl 插件 image.png

特殊 UI

自动计算高度

GridView shrinkWrap

GridViewshrinkWrap 属性决定了是否根据子组件的总长度来调整 GridView 的长度。当 shrinkWrap 设置为 true 时,GridView 会占用其子组件所需要的最小空间,而不是扩展到尽可能大的空间。这在将 GridView 嵌入到无法提供无限空间的组件(如 ListView 或者 Column)中时非常有用,因为它可以防止 GridView 占用更多的空间,导致渲染异常。然而,使用 shrinkWrap 可能会增加性能开销,因为它需要计算子组件的总长度。

GridView.builder(
  shrinkWrap: true,
)

AnimatedSize

Consumer<PackageTabWidgetViewModel>(builder: (BuildContext context, value, Widget? child) {
  return AnimatedSize(
    duration: Duration(milliseconds: 50),
    curve: Curves.easeInOut,
    child: value.model.selectedIndex == 0
        ? ReceivePackageList()
        : SendPackageList(),
  );
})

常见问题

  1. 新增本地图片后加载时报错 Unable to load asset
  • 执行 clean.sh 和 get.sh 脚本
  • 检查pubspec.yaml文件
  1. Command PhaseScriptExecution failed with a nonzero exit code

清除 Flutter 应用的本地缓存 flutter pub cache clean

  1. 执行 flutter doctor 后报错 Xcode installation is incomplete [!] Xcode - develop for iOS and macOS ✗ Xcode installation is incomplete
# 确保 Xcode 已正确配置
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -runFirstLaunch
  1. [Flutter 运行IOS真机,提示无法打开“iproxy”]

在终端输入命令行 sudo xattr -d com.apple.quarantine ${flutter SDK iproxy 路径} 如:sudo xattr -d com.apple.quarantine /Users/xxx/Library/Developer/flutter/bin/cache/artifacts/usbmuxd/iproxy (blog.csdn.net/hzqit520/ar…) image.png

  1. Target of URI doesn't exist: 'package:xxx_image.dart'. Try creating the file referenced by the URI, or Try using a URI for a file that does exist.

执行 Flutter: Clean Project

  1. jaguar_serializer 数据解析报错

flutter packages pub run build\_runner build --delete-conflicting-outputs --verbose 注意在对应的 package 目录执行指令

官网文档 pub.dev/packages/ja…