swift中文文档_Flutter 中文文档:使用 Packages

66549ee39b7a135ae090d5faff82393d.png

使用

Flutter 支持使用其他开发者向 Flutter 和 Dart 生态系统贡献的共享 package,这意味着你可以快速构建应用而不是一切从零开始。

现有的 package 支持许多使用场景,例如,网络请求 (http),自定义导航/路由处理 (fluro),集成设备 API(如 (url_launcher 和 battery,以及使用第三方平台的 SDK(如 Firebase 的 (FlutterFire)。

如果你想添加资源、图片或字体,无论是存储在文件中还是 package 中,请参阅 Flutter 中文文档:添加资源和图片 这篇文档。

1:使用package

下面的内容将为你描述如何使用已经发布了的 packages。

1.1:搜索package

Package 会被发布到 pub.dev。

Pub 网站上的 Flutter 登陆页面 展示了与 Flutter 兼容的 package(即声明的依赖通常与 Flutter 兼容),并且所有已发布的 package 都支持搜索。

1.2:将package依赖添加到应用

要将 package ‘css_colors’ 添加到应用:

(1)添加依赖

打开应用文件夹下的 pubspec.yaml 文件,然后在 pubspec.yaml 下添加 css_colors:。

(2)安装

  • 在命令行中运行:flutter pub get

或者

  • 在 Android Studio/IntelliJ 中点击 pubspec.yaml 文件顶部操作功能区的 Packages get
  • 在 VS Code 中点击位于 pubspec.yaml 文件顶部操作功能区右侧的 Get Packages。

(3)导入

  • 在 Dart 代码中添加相关的 import 语句。

(4)如果有必要,停止并重启应用

  • 如果 package 内有特定平台的代码(Android 的 Java/Kotlin, iOS 的 Swift/Objective-C),代码必须内置到你的应用内。热重载和热重启只对 package 的 Dart 代码执行此操作,所以你需要完全重启应用以避免使用 package 时出现 MissingPluginException 错误。

对于这些步骤,Pub 上任何 package 页面的 Installing tab 选项卡都是一个很方便的参考。

完整示例,参阅下面的 4.1 例子CSS Colors example

1.3:冲突解决

假设你想在应用中使用 some_package 和 other_package,并且它们依赖于不同版本的 url_launcher。于是我们便有了潜在的冲突。避免这种情况的最好方法是 package 的作者在指定依赖项时使用版本范围而非特定版本。

dependencies: url_launcher: ^0.4.2 # Good, any 0.4.x version where x >= 2 works. image_picker: '0.1.1' # Not so good, only version 0.1.1 works.

如果 some_package 声明了以上依赖,并且 another_package 声明了一个兼容的 url_launcher 依赖项,如 '0.4.5' 或 ^0.4.0,pub 能够自动解决冲突问题。类似的注解也适用于插件 package 特定平台 Gradle modules 和/或 CocoaPods 的依赖关系。

即使 some_package 和 another_package 声明了不兼容的 url_launcher 版本,它们实际上仍可能以兼容的方式使用 url_launcher。在这种情况下,可在 pubspec.yaml 文件中添加一个依赖覆盖声明来强制使用特定版本,从而处理冲突。

为了强制使用版本为 0.4.3 的 url_launcher,你可以对应用的 pubspec.yaml 文件做如下更改:

dependencies: some_package: another_package:dependency_overrides: url_launcher: '0.4.3'

如果依赖冲突项不是 package 自身,而是如 guava 这样特定于 Android 的库,那么依赖的覆盖声明必须添加到 Gradle 的构建逻辑中。

为了强制使用版本为 23.0 的 guava,你可以对 android/build.gradle 文件做如下更改:

configurations.all { resolutionStrategy { force 'com.google.guava:guava:23.0-android' }}

CocoaPods 目前尚不提供依赖项覆盖功能。

2. 开发新的 package

如果某个 package 不适用于你的特定需求,你可以开发新的自定义 package(见明日推文)。

3. 管理 package 的依赖和版本

为了使版本冲突的风险最小化,请在 pubspec 文件中指定一个版本范围。

3.1:Package 版本

所有 package 都有一个版本号,在它们的 pubspec.yaml 文件中指定。当前的 package 版本会在其名称旁边显示当前版本号。

当使用简写形式 plugin1: 将 package 添加到 pubspec.yaml 时,表明 plugin1 package 的任何版本都可以被使用。为了确保在更新 package 的时候你的应用不会奔溃,我们建议使用以下格式之一来指定版本范围:

范围限制:指定一个最小和最大的版本号,例如:

dependencies: url_launcher: '>=0.1.2 <0.2.0'

使用 caret 语法 的范围约束与常规的范围约束类似。

dependencies: collection: '^0.1.2'

3.2: 更新 package 依赖

当你添加一个 package 后首次运行 flutter pub get(IntelliJ 中的 ‘Packages Get’),Flutter 将会保存在 pubspec.lock lockfile 中找到的具体 package 版本。这将确保当你或者团队中其他开发者运行 flutter pub get 后能得到相同版本的 package。

如果你想升级到 package 的最新版本,比如使用 package 的最新特性,请运行 flutter packages upgrade(Intellij 中的 flutter packages upgrade)。这将检索你在 pubspec.yaml 文件中指定的版本约束所允许的最高可用版本。

3.3 依赖未发布的 package

即使未在 Pub site 上发布,也可以使用 package。对于不用于公开发布的私有插件,或者尚未准备好发布的 package,可以使用其他依赖选项。

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

dependencies: plugin1: path: ../plugin1/

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

dependencies: plugin1: git: url: git://github.com/flutter/plugin1.git

Git 依赖于文件夹中的 package:默认情况下,Pub 假定 package 位于 Git 仓库的根目录。如果不是这种情况,你可以使用 path 参数指定位置,例如:

dependencies: package1: git: url: git://github.com/flutter/packages.git path: packages/package1

最后,你可以使用 ref 参数将依赖固定到 git 特定的 commit、branch 或者 tag。

4. 例子

下面的示例将介绍使用 packages 的一些必要步骤。

4.1 例子:使用 CSS Colors package

css_colors package 为 CSS 颜色定义颜色常量,允许你在 Flutter 框架中任何需要 Color 类型的地方使用它们。

要使用这个 package:

(1)创建一个名为 cssdemo 的新项目

(2)打开 pubspec.yaml,并添加依赖 css-colors:

dependencies: flutter: sdk: flutter

替换为:

dependencies: flutter: sdk: flutter css_colors: ^1.0.0

(3)在命令行中运行 flutter packages get,或者点击 Intellij 中的 Packages get

(4)打开 lib/main.dart 并将其全部内容替换为:

 import 'package:css_colors/css_colors.dart'; import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: DemoPage(), ); } } class DemoPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold(body: Container(color: CSSColors.orange)); } }

(5)运行应用。当你点击 ‘Show Flutter homepage’ 时,你将看到手机默认浏览器打开并出现 Flutter 主页。

4.2 例子:使用 url_launcher package 来打开浏览器

url_launcher 插件允许你在移动平台上打开默认浏览器以显示给定的 URL。它演示了 package 如何也可能包含特定于平台的代码(我们将这些 package 称为插件)。它同时支持 Android 和 iOS。

要使用这个插件:

(1)新建一个名为 ‘lauchdemo’ 的新项目

(2)打开 pubspec.yaml,然后添加依赖 url_launcher:

dependencies: flutter: sdk: flutter

替换为:

dependencies: flutter: sdk: flutter url_launcher: ^0.4.1

(3)在命令行中运行 flutter packages get,或者点击 Intellij 中的 ‘Packages get’

(4)打开 lib/main.dart 并将其全部内容替换为:

 import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: DemoPage(), ); } } class DemoPage extends StatelessWidget { launchURL() { launch('https://flutter.dev'); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: RaisedButton( onPressed: launchURL, child: Text('Show Flutter homepage'), ), ), ); } }

(5)运行应用(如果你的应用在添加插件之前已经运行,请停止并重启应用)。当你点击 Show Flutter homepage 时,你将看到手机默认浏览器打开并出现 Flutter 主页。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在上一篇文章中,我们实现了微信悬浮窗的拖动功能。本篇文章将继续讲解如何实现微信悬浮窗的缩放功能。 ## 实现思路 微信悬浮窗的缩放功能可以通过手势识别来实现。具体来说,当用户使用两个手指捏合或张开时,我们可以识别出缩放手势,并按照缩放手势的大小来更新悬浮窗的大小。 ## 实现步骤 1. 定义缩放手势识别器。 ```dart final scaleGestureDetector = ScaleGestureRecognizer(); ``` 2. 在 initState 方法中,将缩放手势识别器添加到 GestureDetector 中。 ```dart @override void initState() { super.initState(); // 添加缩放手势识别器 scaleGestureDetector ..onScaleStart = _handleScaleStart ..onScaleUpdate = _handleScaleUpdate ..onScaleEnd = _handleScaleEnd; } @override Widget build(BuildContext context) { return GestureDetector( onLongPressMoveUpdate: _handleDragUpdate, onLongPressEnd: _handleDragEnd, child: CustomPaint( size: Size(widget.width, widget.height), painter: _FloatWindowPainter(), ), // 添加缩放手势识别器 scaleGestureDetector: scaleGestureDetector, ); } ``` 3. 在 _handleScaleUpdate 方法中,根据缩放手势的大小来更新悬浮窗的大小。 ```dart void _handleScaleUpdate(ScaleUpdateDetails details) { // 计算缩放比例 double scale = details.scale; if (scale < 1.0) { // 缩小悬浮窗 widget.width *= scale; widget.height *= scale; } else { // 放大悬浮窗 widget.width += (details.scale - 1.0) * widget.width; widget.height += (details.scale - 1.0) * widget.height; } // 更新悬浮窗位置 _updatePosition(); // 通知父组件更新悬浮窗大小 widget.onSizeChanged(widget.width, widget.height); // 刷新界面 setState(() {}); } ``` 4. 在 _handleScaleEnd 方法中,重置缩放手势识别器。 ```dart void _handleScaleEnd(ScaleEndDetails details) { // 重置缩放手势识别器 scaleGestureDetector.dispose(); scaleGestureDetector ..onScaleStart = _handleScaleStart ..onScaleUpdate = _handleScaleUpdate ..onScaleEnd = _handleScaleEnd; } ``` ## 完整代码 ```dart import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; class FloatWindow extends StatefulWidget { final double x; final double y; double width; double height; final Widget child; final Function(double, double) onPositionChanged; final Function(double, double) onSizeChanged; FloatWindow({ Key key, this.x, this.y, this.width, this.height, this.child, this.onPositionChanged, this.onSizeChanged, }) : super(key: key); @override _FloatWindowState createState() => _FloatWindowState(); } class _FloatWindowState extends State<FloatWindow> { Offset _offset = Offset.zero; Offset _position = Offset.zero; bool _dragging = false; final scaleGestureDetector = ScaleGestureRecognizer(); @override void initState() { super.initState(); // 添加缩放手势识别器 scaleGestureDetector ..onScaleStart = _handleScaleStart ..onScaleUpdate = _handleScaleUpdate ..onScaleEnd = _handleScaleEnd; } @override Widget build(BuildContext context) { return GestureDetector( onLongPressMoveUpdate: _handleDragUpdate, onLongPressEnd: _handleDragEnd, child: CustomPaint( size: Size(widget.width, widget.height), painter: _FloatWindowPainter(), ), // 添加缩放手势识别器 scaleGestureDetector: scaleGestureDetector, ); } @override void dispose() { // 释放缩放手势识别器 scaleGestureDetector.dispose(); super.dispose(); } void _handleScaleStart(ScaleStartDetails details) { // 记录当前悬浮窗大小 widget.width = context.size.width; widget.height = context.size.height; } void _handleScaleUpdate(ScaleUpdateDetails details) { // 计算缩放比例 double scale = details.scale; if (scale < 1.0) { // 缩小悬浮窗 widget.width *= scale; widget.height *= scale; } else { // 放大悬浮窗 widget.width += (details.scale - 1.0) * widget.width; widget.height += (details.scale - 1.0) * widget.height; } // 更新悬浮窗位置 _updatePosition(); // 通知父组件更新悬浮窗大小 widget.onSizeChanged(widget.width, widget.height); // 刷新界面 setState(() {}); } void _handleScaleEnd(ScaleEndDetails details) { // 重置缩放手势识别器 scaleGestureDetector.dispose(); scaleGestureDetector ..onScaleStart = _handleScaleStart ..onScaleUpdate = _handleScaleUpdate ..onScaleEnd = _handleScaleEnd; } void _handleDragUpdate(LongPressMoveUpdateDetails details) { if (!_dragging) { _dragging = true; _offset = Offset(widget.x, widget.y); } setState(() { _position = _offset + details.offset; widget.onPositionChanged(_position.dx, _position.dy); }); } void _handleDragEnd(LongPressEndDetails details) { _dragging = false; } void _updatePosition() { if (_position.dx + widget.width / 2 > MediaQuery.of(context).size.width) { _position = Offset( MediaQuery.of(context).size.width - widget.width / 2, _position.dy, ); } if (_position.dx - widget.width / 2 < 0) { _position = Offset(widget.width / 2, _position.dy); } if (_position.dy + widget.height / 2 > MediaQuery.of(context).size.height) { _position = Offset( _position.dx, MediaQuery.of(context).size.height - widget.height / 2, ); } if (_position.dy - widget.height / 2 < 0) { _position = Offset(_position.dx, widget.height / 2); } widget.onPositionChanged(_position.dx, _position.dy); } } class _FloatWindowPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) {} @override bool shouldRepaint(_FloatWindowPainter oldDelegate) { return false; } } ``` ## 总结 本篇文章讲解了如何使用手势识别器来实现微信悬浮窗的缩放功能。通过本篇文章的学习,你已经掌握了手势识别器的使用方法,以及如何在自绘组件中使用手势识别器。在下一篇文章中,我们将讲解如何实现微信悬浮窗的旋转功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值