Flutter开发中插件使用

2023-10-27

flutter的库是以package的方式来管理的。Package 分为两种:

  • Dart package:它只能使用 Dart 和 Flutter 提供的 API,使用纯dart语言开发。一些Dart包可能包含Flutter特定功能,因此对Flutter框架具有依赖性。
  • plugin package:使用 Dart 编写的,按需使用 Java 或 Kotlin、ObjC 或 Swift 分别在 Android 和/或 iOS 平台实现的 package。可以获取平台信息,比如电量、陀螺仪等。

添加依赖

Package 会被发布到 pub.dev 网站上。中文镜像dev.flutter-io。加载速度更快。

  • 添加依赖

    • 打开应用文件夹下的pubspec.yaml文件。然后添加dio:,例如:

        dependencies:
          dio:^3.0.9 #latest version
      复制代码

      ^3.0.9 表示一系列版本,^2.0.1的意思是从2.0.1开始到3.0.0但不包含3.0.0的一系列版本。我们也可以指定依赖库的为特定的版本:

      • any:任意版本
      • 1.2.3:特定的版本
      • <1.2.3:小于 1.2.3 的版本,此外还有 <=、>、>= 可以使用
      • ‘>=1.2.3 <2.0.0’ 指定一个范围
  • 安装

    • 在命令行中运行:flutter pub get
      注意:必须与pubspec.yaml文件在同一文件夹下执行该命令。否则提示找不到命令。

      或者

    • 在 Android Studio/IntelliJ 中点击 pubspec.yaml 文件顶部操作功能区的 Packages get

  • 添加依赖的其他方式

    • Path依赖

      Flutter 应用可以通过文件系统 path: 依赖而依赖插件。路径可以是相对的也可以是绝对的。例如,要依赖位于应用相邻目录中的插件 plugin1,可以使用以下语法:

      dependencies:
        plugin1:
          path: ../plugin1/
      复制代码
    • git依赖

      你也可以依赖存储在 Git 仓库中的 package,如果 package 位于仓库的根目录,可以使用以下语法:

      dependencies:
        plugin1:
          git:
            url: git://github.com/flutter/plugin1.git
      复制代码

      默认情况下,pub 工具会默认假定 package 位于 Git 仓库的根目录。如果不是这种情况,你可以使用 path 参数指定位置,例如:

      dependencies:
        package1:
          git:
            url: git://github.com/flutter/packages.git
            path: packages/package1
      复制代码

      最后,你可以使用 ref 参数将依赖固定到 git 特定的 commit、branch 或者 tag。更多详细信息,请参阅 Package dependencies

  • 升级依赖

    第一次获取依赖时,Pub 会下载依赖及其兼容的最新版本。然后通过创建 lockfile 锁定依赖,以始终使用这个版本。 Pub 会在 pubspec 旁创建并存储一个名为 pubspec.lock 文件。它列出了使用的每个依赖包的指定版本(当前包或传递包的版本)。

    使用命令 pub upgrade :

      $ pub upgrade
    复制代码

    上面的命令用于重新生成 lockfile 文件,并使用最新可用版本的依赖包。如果仅升级某个依赖,可以在命令中指定需要升级的包:

      $ pub upgrade xxx
    复制代码

    上面的命令升级 xxx 到最新版本,但维持其它包不变。

插件开发

创建一个dart package

通过使用 packages (的模式)可以创建易于共享的模块化代码。一个最基本的 package 由以下内容构成:

下图展示了最简单的Dart package布局:

pubspec.yaml 文件

用于定义 package 名称、版本号、作者等其他信息的元数据文件。

lib 目录

包含共享代码的 lib 目录,其中至少包含一个 .dart 文件。lib目录下的dart代码对于其他package是公开的。你可以根据需要在 lib 下任意创建组织文件结构。按照惯例,实现代码会放在 lib/src 目录下。 lib/src 目录下的代码被认为是私有的。其他 Package 应该永远不需要导入 src/... 目录下代码。

  • Step 1: 创建package
    想要创建纯 Dart 库的 package,请使用带有 --template=package标志的 flutter create 命令:

      $ cd somepath
      $ flutter create --template=package hello
    复制代码
  • Step 2: 实现package
    对于纯 Dart 库的 package,只要在 lib/.dart 文件中添加功能实现,或在 lib 目录中的多个文件中添加功能实现。
    如果要对 package 进行测试,在 test 目录下添加 单元测试。

创建一个plugin package

如果想要开发一个调用特定平台 API 的 package,你需要开发一个原生插件 packgae。原生插件 packgae 是 Dart package 的特别版本,除了要实现 Dart package 要实现的内容,还需要按需使用 Java 或 Kotlin、ObjC 或 Swift 分别在 Android 和/或 iOS 平台实现,你可以使用 [platform channels][] 中的 API 来实现特定平台的调用。

  • Step 1: 创建package
    想要创建原生插件 package,请使用带有 --template=plugin 标志的 flutter create 命令。

    使用 --org 选项,以反向域名表示法来指定你的组织。该值用于生成的 Android 及 iOS 代码。

    使用 -a 选项指定 Android 的语言,或使用 -i 选项指定 iOS 的语言。请选择以下 任一项:

      $ flutter create --org com.example --template=plugin -a kotlin hello
      $ flutter create --org com.example --template=plugin -a java hello
      $ flutter create --org com.example --template=plugin -i objc hello
      $ flutter create --org com.example --template=plugin -i swift hello
    复制代码

    通过该命令创建的hello插件主要包括以下内容:

    • lib/hello.dart 文件
      Dart 插件 API 实现。

    • android/src/main/java/com/example/hello/HelloPlugin.kt 文件
      Android 平台原生插件 API 实现(使用 Kotlin 编程语言)。

    • ios/Classes/HelloPlugin.m 文件
      iOS 平台原生插件 API 实现(使用 Objective-C 编程语言)。

    • example/ 文件
      一个依赖于该插件并说明了如何使用它的 Flutter 应用。

  • Step 2: 实现package
    • 步骤a:定义 package API(.dart)
      原生插件类型 package 的 API 在 Dart 代码中要首先定义好,使用你钟爱的 Flutter 编辑器,打开 hello 主目录,并找到 lib/hello.dart 文件。

    • 步骤b:添加 Android 平台代码(.kt/.java)
      我们建议你使用 Android Studio 来编辑 Android 代码。使用 Android Studio 编辑Android 平台代码之前,首先确保代码至少被构建过一次(换句话说,即从 IDE/编辑器执行示例程序,或在终端中执行以下命令:cd hello/example; flutter build apk)。

      接下来进行如下步骤:

      1. 启动 Android Studio.
      2. 在 “Welcome to Android Studio” 对话框中选择 “Import project”,或在菜单中选择“File > New > Import Project…”,然后选择 hello/example/android/build.gradle 文件;
      3. 在“Gradle Sync”对话框中,选择“OK”;
      4. 在“Android Gradle Plugin Update”对话框中,选择“Don’t remind me again for this project”。
    • 步骤c:添加 iOS 平台代码(.swift/.h+.m)
      我们建议你使用 Xcode 来编辑 iOS 代码。使用 Xcode 编辑 iOS 平台代码之前,首先确保代码至少被构建过一次(即从 IDE/编辑器执行示例程序,或在终端中执行以下命令: cd hello/example; flutter build ios --no-codesign)。

      接下来执行下面步骤:

      1. 启动 Xcode
      2. 选择“File > Open”,然后选择 hello/example/ios/Runner.xcworkspace 文件。
    • 步骤d:关联 API 和平台代码
      最后将dart编写的代码和平台代码通过channel实现互联。

Flutter与平台通信

Flutter采用MethodChannel与各平台进行通信,如下图所示:

消息是以异步的形式进行传递,以确保用户界面能够保持响应。
需要注意的是,上图中的箭头是双向的。也就是说,我们不仅可以从 Flutter 调用 Android/iOS 的代码,也可以从 Android/iOS 调用 Flutter。调用时相关的参数对应如下:

PlatformChannel功能简介

1

. PlatformChannel类说明:

  • BasicMessageChannel: 用于传递数据。Flutter与原生项目的资源是不共享的,可以通过BasicMessageChannel来获取Native项目的图标等资源。
  • MethodChannel: 传递方法调用。Flutter主动调用Native的方法,并获取相应的返回值。比如获取系统电量,发起Toast等调用系统API,可以通过这个来完成。
  • EventChannel: 传递事件。这里是Native将事件通知到Flutter。比如Flutter需要监听网络情况,这时候MethodChannel就无法胜任这个需求了。EventChannel可以将Flutter的一个监听交给Native,Native去做网络广播的监听,当收到广播后借助EventChannel调用Flutter注册的监听,完成对Flutter的事件通知。

2

. 消息编解码MessageCodec有4个子类:

  • StandardMessageCodec
    StandardMessageCodec是BasicMessageChannel的默认编解码器,其支持基础数据类型、二进制数据、列表、字典,其工作原理会在下文中详细介绍。
  • StringCodec
    StringCodec用于字符串与二进制数据之间的编解码,其编码格式为UTF-8。
  • JSONMessageCodec
    JSONMessageCodec用于基础数据与二进制数据之间的编解码,其支持基础数据类型以及列表、字典。其在iOS端使用了NSJSONSerialization作为序列化的工具,而在Android端则使用了其自定义的JSONUtil与StringCodec作为序列化工具。
  • BinaryCodec
    BinaryCodec是最为简单的一种Codec,因为其返回值类型和入参的类型相同,均为二进制格式(Android中为ByteBuffer,iOS中为NSData)。实际上,BinaryCodec在编解码过程中什么都没做,只是原封不动将二进制数据消息返回而已。或许你会因此觉得BinaryCodec没有意义,但是在某些情况下它非常有用,比如使用BinaryCodec可以使传递内存数据块时在编解码阶段免于内存拷贝。

3

. 方法编解码MethodCodec有两个子类:

  • StandardMethodCodec
    MethodCodec的默认实现,StandardMethodCodec的编解码依赖于StandardMessageCodec,当其编码MethodCall时,会将method和args依次使用StandardMessageCodec编码,写入二进制数据容器。其在编码方法的调用结果时,若调用成功,会先向二进制数据容器写入数值0(代表调用成功),再写入StandardMessageCodec编码后的result。而调用失败,则先向容器写入数据1(代表调用失败),再依次写入StandardMessageCodec编码后的code,message和detail。
  • JSONMethodCodec
    JSONMethodCodec的编解码依赖于JSONMessageCodec,当其在编码MethodCall时,会先将MethodCall转化为字典{"method":method,"args":args}。其在编码调用结果时,会将其转化为一个数组,调用成功为[result],调用失败为[code,message,detail]。再使用JSONMessageCodec将字典或数组转化为二进制数据。

4

. 通信工具BinaryMessager

BinaryMessenger是Platform端与Flutter端通信的工具,其通信使用的消息格式为二进制格式数据。当我们初始化一个Channel,并向该Channel注册处理消息的Handler时,实际上会生成一个与之对应的BinaryMessageHandler,并以channel name为key,注册到BinaryMessenger中。当Flutter端发送消息到BinaryMessenger时,BinaryMessenger会根据其入参channel找到对应的BinaryMessageHandler,并交由其处理。

Binarymessenger并不知道Channel的存在,它只和BinaryMessageHandler打交道。而Channel和BinaryMessageHandler则是一一对应的。由于Channel从BinaryMessageHandler接收到的消息是二进制格式数据,无法直接使用,故Channel会将该二进制消息通过Codec(消息编解码器)解码为能识别的消息并传递给Handler进行处理。

当Handler处理完消息之后,会通过回调函数返回result,并将result通过编解码器编码为二进制格式数据,通过BinaryMessenger发送回Flutter端。

具体实现

BasicMessageChannel

  • flutter端代码

    BasicMessageChannel _basicMessageChannel = BasicMessageChannel('my_flutter.io/message', StandardMessageCodec());
    
    BasicMessageChannel _basicMessageChannel2 = BasicMessageChannel('my_flutter.io/message2', StandardMessageCodec());
    
    Future<void> _sendMessage() async {
      String reply = await _basicMessageChannel.send('发送给Native端的数据');
        debugPrint(reply);
      }
    
    void receiveMessage() {
      _basicMessageChannel2.setMessageHandler((message) async {
    	debugPrint("message : $message");
    	return '返回给Native端';
      });
    }
    复制代码

    注意 native端像flutter发送消息时,需注意时机,待flutter注册监听后,才能收到native的消息。

  • native(ios)端代码

    let basicChannel = FlutterBasicMessageChannel(name: "my_flutter.io/message", binaryMessenger: flutterViewController.binaryMessenger)
      
    basicChannel.setMessageHandler { (message, reply) in
      debugPrint(message ?? "my flutter!")
      reply("返回给Flutter端的数据")
    }		
      		
      		
    let basicChannel2 = FlutterBasicMessageChannel(name: "my_flutter.io/message2", binaryMessenger: flutterViewController.binaryMessenger)
      
    basicChannel2.sendMessage("发送给Flutter端数据") { (reply) in
      debugPrint(reply ?? "")
    }
    复制代码

MethodChannel

  • flutter端代码

    static const platform = const MethodChannel('samples.flutter.dev/battery');
    Future<void> _getBatteryLevel() async {
      String batteryLevel;
      try {		
        final int result = await platform.invokeMethod('getBatteryLevel');
        batteryLevel = 'Battery level at $result % .';
      } on PlatformException catch (e) {
        batteryLevel = "Failed to get battery level: '${e.message}'.";
      }
    
      setState(() {
        debugPrint("batteryLevel : $batteryLevel");
        _batteryLevel = batteryLevel;
      });
    }
    复制代码
  • native端代码

    let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
      										binaryMessenger: flutterViewController.binaryMessenger)
    batteryChannel.setMethodCallHandler({
      (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
        // Note: this method is invoked on the UI thread.
        guard call.method == "getBatteryLevel" else {
        result(FlutterMethodNotImplemented)
        return
      }
    self.receiveBatteryLevel(result: result)
    })
    
    
    private func receiveBatteryLevel(result: FlutterResult) {
      let device = UIDevice.current
      device.isBatteryMonitoringEnabled = true
      if device.batteryState == UIDevice.BatteryState.unknown {
      result(FlutterError(code: "UNAVAILABLE",
      				message: "Battery info unavailable",
      				details: nil))
      } else {
        result(Int(device.batteryLevel * 100))
      }
    }
    复制代码

EventChannel

  • flutter

    //声明eventChannel实例
    static const _eventChannel = EventChannel('flutter.io/event');
    
    //定义两个回调方法
    void _onData(Object data) {
      debugPrint("data: $data");
      if (data is String) {
      setState(() {
        _orientation = data;
      });
     }
    }
    
    void _onError(Object error) {
      debugPrint("error : $error");
      PlatformException exception = error;
      setState(() {
        _orientation = exception?.message ?? 'unknown.';
      });
    }
    
    //设置监听
    _eventChannel.receiveBroadcastStream().listen(_onData, onError: _onError);
    复制代码
  • native

    let eventChannel = FlutterEventChannel(name: "flutter.io/event", binaryMessenger: flutterViewController.binaryMessenger)
    eventChannel.setStreamHandler(self)
    
    //定义一个全局的回调
    var sink: FlutterEventSink? = nil
    
    //这是两个flutter引擎的回调方法
    //flutter开始监听这个channel时的回调, arguments是flutter传给native的参数,event作为native给flutter回调使用。
    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
      sink = events
      // arguments flutter给native的参数
      events("portrait")
    
      NotificationCenter.default.addObserver(self, selector: #selector(self.onBatteryStateDidChange(_:)), name:UIDevice.orientationDidChangeNotification, object: nil)
    
      return nil;
    }	
      
    //flutter不再监听回调
    func onCancel(withArguments arguments: Any?) -> FlutterError? {
      sink = nil
      return nil
    }		
    
    @objc func onBatteryStateDidChange(_ notification: NotificationCenter) {
      let orientation = UIDevice.current.orientation
    
      switch orientation {
      case .portrait:
      	sink?("portrait")
      case .portraitUpsideDown:
      	sink?("portraitUpsideDown")
      case .landscapeLeft:
      	sink?("landscapeLeft")
      case .landscapeRight:
      	sink?("landscapeRight")
      case .faceUp:
      	sink?("faceUp")
      case .faceDown:
      	sink?("faceDown")
      default:
      	sink?("unknown")
      }
    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter开发中插件使用 的相关文章

  • Android 应用程序安装失败:包 com.my.app 在条目 AndroidManifest.xml 处没有证书

    在 Android Studio 中 我生成了带有密钥库等的签名 APK 将 APK 安装到设备上时失败 并显示 无法安装应用程序 并且在 Android Monitor 中我看到以下行 Package com my app has no
  • 如何从Firebase Firestore实时更新文档中获取修改后的字段或数据? [复制]

    这个问题在这里已经有答案了 我有多个文档 我的问题是我无法获取修改的特定数据 我正在获取完整的文档 db collection employees whereEqualTo OID OID addSnapshotListener new E
  • 使用 Fragment 在工具栏中实现 SearchView

    当前情况 我的应用程序主页由导航抽屉组成 因此我将视图作为片段加载 我的工具栏中也有搜索图标 我在中实现了它menu xml 下一步我实施了SearchView通过以下问题的答案来获取搜索图标在工具栏中实现搜索 https stackove
  • 拖动时跳转 ImageView。 getX() 和 getY() 值正在跳跃

    我创建了一个用于拖动视图的 onTouchListener 如果我使用的话 图像可以顺利拖动getRawX and getRawY 问题是 当您向下放置第二个指针然后抬起第一个指针时 图像将跳转到第二个指针 此 onTouchListene
  • 在 gradle 中,我应该排除分支下的所有依赖项还是只排除根就足够了?

    我已将以下自定义任务添加到我的build gradlefile 为了打印出依赖项的依赖项 This part is useful for finding conflict resolution s between dependencies
  • 如何通过我的活动在 Android 中设置铃声?

    我正在尝试找到一种方法来通过 Android 活动中的代码设置新的默认铃声 我已经将铃声下载到bytearray 最后 我设法将默认铃声设置为我下载的铃声 下面不包含下载代码 仅包含将其设置为默认铃声所需的代码 File k new Fil
  • 为什么反射会减慢Android手机的速度

    我多次读到反射会降低手机性能 这有多真实 例如 在我的例子中 我从 Web 服务获取一些参数 这些参数与我在 Android 应用程序中的类的参数同名 所以我只是使用java字段和反射设置这些参数的值 它似乎并没有降低性能 有人可以向我解释
  • Android 全屏对话框确认和拒绝操作

    材料设计中的全屏对话框应该在操作栏 工具栏上有确认和拒绝操作 我的问题是 我该怎么做 显示对话框 getFragmentManager beginTransaction add R id container new MyDialogFrag
  • HMS 核心地图套件在我的 Android 应用程序上根本无法工作

    我正在尝试在我的应用程序中使用华为 HMS 地图套件 我对整体地图很陌生 无论是来自谷歌还是华为 我按照文档中的教程以及华为提供的代码实验室中的说明进行操作 并将我的代码在一起 但是当我运行地图活动时 什么也没有出现 我得到的只是一个空白活
  • 透明 9patch 图像:显示出线条

    我得到了一个透明的 9 补丁图像 其中有 9 条补丁线显示槽 This is the output 显然我不希望水平线可见 这就是我创建 9patch 的方式 This is the final image that is used in
  • 如何将 Android 添加到 Phonegap 平台版本 3

    经过大量挖掘 我相信这个问题 https stackoverflow com questions 18423444 phonegap 3 doesnt work with andriod studio与我没有添加任何用于构建phonegap
  • Android NDK 代码中的 SIGILL

    我在市场上有一个 NDK 应用程序 并获得了有关以下内容的本机崩溃报告 SIGILL信号 我使用 Google Breakpad 生成本机崩溃报告 以下是详细信息 我的应用程序是为armeabi v7a with霓虹灯支持 它在 NVIDI
  • 如何通过 Android 按钮单击运行单独的应用程序

    我尝试在 Android 应用程序中添加两个按钮 以从单独的两个应用程序订单系统和库存系统中选择一个应用程序 如图所示 我已将这两个应用程序实现为两个单独的 Android 项目 当我尝试运行此应用程序时 它会出现直到正确选择窗口 但是当按
  • 哪个视图最亮?

    在Android中 哪个是轻量级视图 例如 View Textview Edittext 等 在某些情况下 我们需要使用视图来填充区域而不向用户显示视图 同时屏幕加载速度应该很快 您可以使用空间 android widget Space S
  • Android SearchView 在启动时隐藏键盘

    我有一个小问题正在尝试解决 当我打开应用程序时 键盘会显示输入搜索视图的查询 不过 我只想在单击搜索视图时显示键盘 我该如何解决 Thanks 这对我有用 用于隐藏焦点的代码 searchView SearchView view findV
  • 受信任的网络活动 - 地址栏不隐藏(Android 72 的 Chrome)

    我已经关注了this https developers google com web updates 2017 10 using twa了解如何使用受信任的 Web 活动的指南 一切正常 但地址栏仍然出现 一开始我认为这是因为当应用程序正在
  • 如何将样式应用于我拥有的所有 TextView? [复制]

    这个问题在这里已经有答案了 可能的重复 设计所有 TextView 或自定义视图 的样式 而不向每个 TextView 添加样式属性 https stackoverflow com questions 6801890 styling all
  • 丢失应用程序的密钥库文件(但已启用 Google Play 应用程序签名)

    我已经失去了原来的keystore用于签署我的应用程序的文件 我的应用启用了 Google Play 应用签名 如果我联系 Google 支持人员 是否可以重置密钥 以便我可以继续上传到此包 我希望我可以做到这一点 因为应用程序签名已启用
  • 检查应用程序是否在 Android Market 上可用

    给定 Android 应用程序 ID 包名称 如何以编程方式检查该应用程序是否在 Android Market 上可用 例如 com rovio angrybirds 可用 而 com random app ibuilt 不可用 我计划从
  • 如何访问我的 Android 程序中的联系人

    我正在制作一个短信应用程序 并且想要访问我的 Android 应用程序中的联系人 我想访问联系人 就像他们在实际联系人列表中一样 选择后 我需要返回到我的活动 在其中我可以向该人发送短信 或者是否可以访问存储联系人的数据库 我的代码如下所示

随机推荐

  • [python爬虫] Selenium切换窗口句柄及调用Chrome浏览器

    因为我的博客是根据我每个阶段自己做的事情而写的 所以前言可能有点跑题 但它更有利于让我回忆这个阶段自己的所作所为 这篇文章主要介绍Selenium爬虫获取当前窗口句柄 切换窗口句柄以及调用Chrome浏览器几个知识点 其中获取当前句柄的方法
  • 三元操作符

    通常N元操作符指的是该操作符有N个操作数 如赋值操作符 它是一个二元操作符 所以它有两个操作数 左右各一个 又如减号 是一个二元操作符 但是当它作为负号 使用的时候 便是一个一元操作符 它表示负数 所以只有一个操作数 那么 三元操作符理应有
  • python--unicodedata用法

    python unicodedata用法 需要掌握的 1 将Unicode字符 chr 转换为等效的数值 以浮点形式返回 print unicodedata numeric 四 4 0 2 将unicode字符 chr 转换为其等效的数字值
  • 【C语言初学必看】猜数字游戏背后的知识

    目录 前言 1 先看主体部分 大体逻辑的部分 a 为什么用do while循环 b switch语句 c 关于scanf 中的 d s 和 printf 的关系 d menu 和game 函数为什么没有返回值 e 为什么 intput 在w
  • ABAP 351 - 动态编程

    作为面对对象的编程语言 ABAP也是支持动态编程的 ABAP351作为一门独立的课程介绍了类反射机制如何实现的过程 一 Field Symbols Field Symbols 字段符号 在ABAP编程中经常使用 实际上它具备以下几点特性 字
  • citespace教程

    参考视频教程 CiteSpace保姆级教程1 文献综述怎么写 研究生写文神器 手把手教你做科学知识图谱 以中国知网为例 哔哩哔哩 bilibili Citespace 从下载到图谱分析 详细教程 基于CNKI和WOS 陈同学 哔哩哔哩 bi
  • “数”说程序员|“后浪”涌袭下的开发者现状

    红网时刻长沙10月23日讯 见习记者 赵翼鹏 10月23日至25日 长沙 中国1024程序员节 将盛大举行 为期3天的会议将以开源为主议题进行讨论 并包括了十多场技术论坛 多位操作系统领域大咖还将史上首次在岳麓山展开对话 为什么会是1024
  • BUCK和BOOST电路详解

    1 BUCK电路 BUCK是一种降压型电路 他的特征就是输出电压低于输入电压 输入的电流是脉动的 输出的电流是连续的 BUCK电路的原理图如下图所示 当开关管Q1驱动为高电平时 开关管导通 电感L1被充磁储能 流过电感的电流线性增加 同时给
  • 《无码的青春》第七章 御姐

    之前我们各有各的故事 各有各的守护 然而今天却成了同一类人 失去了各自的女神 失去了自己的信仰 没有了牵挂 也不再需要对什么人负责 四个单身男人 在这个浮华的城市里尽情的释放着过剩的荷尔蒙 周末我们会聚在道哥的酒吧里 在浮光掠影的酒精和静静
  • python3的turtle画模仿3d星空,运动的恒星小宇宙

    本文参考原文 http bjbsair com 2020 03 25 tech info 6248 html 1 宇宙 2 代码实现条件 python3 3 第1步 第1步 导入模块 from turtle import from rand
  • 8.Xaml Border控件

    1 运行图片 2 运行源码
  • 自定义滚动条@莫成尘

    先看代码 复制使用即可 以下代码均可复制粘贴使用 我将以注释的形式解释代码左右 您将看到以下效果 原生的滚动条比较方正 不够圆滑 很大程度上不能满足我们的审美 有时候需要修改其样式 滚动条的高度将随着内容的多少自适应
  • GOTC演讲回顾

    5月27 28日 由上海浦东软件园 开放原子开源基金会 Linux基金会亚太区和开源中国联合发起的2023全球开源技术峰会 Global Open source Technology Conference GOTC 在上海圆满召开 大会聚焦
  • Redis IO 多路复用底层的实现原理

    文章目录 前言 用户空间与内核空间 PIO 和 DMA PIO DMA 缓存I O和直接I O 缓存I O的读写操作 缓存I O的优点 缓存I O的缺点 直接I O的优点 IO的访问方式 磁盘IO 网络IO 磁盘IO和网络IO对比 同步IO
  • AG表格基础滚动分页-React版本

    AG表格滚动分页文档 AG表格在使用滚动分页时 不可使用rowData属性做为数据源 传入表格 因为AG的滚动分页 使用的是特殊表模型 所有正常模型下的API有可能会失效 使用AG滚动分页时 需把正常数据模型替换成滚动分页数据模型 示例 t
  • 30天自制操作系统学习-第2天

    第二天主要学习汇编语言与Makefile入门 1 继续开发 在这里先给出作者在第二天使用nask编写代码中涉及到的寄存器概念 AX accumulator 累加寄存器 CX counter 计数寄存器 DX data 数据寄存器 BX ba
  • 反射工具类导入Excel数据到数据库

    1 工作类代码 import org apache poi hssf usermodel HSSFWorkbook import org apache poi ss usermodel import org apache poi xssf
  • ubuntu20.04换国内清华源和安装docker

    写在前面 安装好ubuntu双系统后 默认的软件更新源是国外的 在国内使用速度很慢 用 apt install xxx 安装软件时可能出现 网络不可达 你的网络需要认证吗 无法定位软件包 等错误 所以我们需要更换成国内的源 这样才能正常安装
  • c++读写文件操作

    程序的运行产生的数据都是临时数据 不能持久的保存 一旦程序运行结束数据就会被释放 在C 中对文件进行操作必须包含头文件
  • Flutter开发中插件使用

    flutter的库是以package的方式来管理的 Package 分为两种 Dart package 它只能使用 Dart 和 Flutter 提供的 API 使用纯dart语言开发 一些Dart包可能包含Flutter特定功能 因此对F