android studio真机调试_Flutter实战经验(四):使用原生的调试器

c4f28fd430174eef3136405ca24f2c17.png

使用原生的调试器

如果你只使用 Dart 语言开发 Flutter 应用,并且不使用特定于平台的的库或者功能,你可以使用 IDE 的调试器调试你的代码。只有这篇指南的第一部分「调试 Dart 代码」对你有用。

如果你正在开发特定于平台的的插件或者使用由 Swift,ObjectiveC,Java 或 Kotlin 语言编写的特定于平台的库,你可以使用 Xcode(用于 iOS)或者 Android Gradle(用于 Android)调试这部分代码。本文介绍如何将用于 Dart 和用于原生代码的 两个 调试器连接到你的 Dart 应用。

1. 调试 Dart 代码

你可以使用 IDE 进行一般的 Dart 调试。以下内容针对 Android Studio 进行说明,但你也可以使用你喜欢的安装并配置好 Flutter 和 Dart 插件的编辑器来进行调试。

小提示:

推荐连接到真机进行调试,而不是使用不支持 profie 构建模式的仿真器或模拟器。更多信息参考 :Flutter实战经验(三):构建模式的选择

1.1 Dart 调试器

  • 使用 Android Studio 打开你的项目。
  • 通过单击调试图标,同时打开调试面板并在控制台中运行应用。首次运行应用是最慢的,你会发现窗口底部的调试面板看起来会像这样:
9a521c0c48877ec5360d543b26e529e6.png

调试面板

你可以设置调试面板的显示位置,甚至可以用调试面板右侧的齿轮将其拆分到独立的窗口。对于 Android Studio 中的任何检查器都是如此。

  • 在 counter++ 这一行上添加断点。
  • 在应用里,点击 + 按钮(FloatingActionButton,或者简称 FAB)来增加数字。应用会暂停。
  • 以下截图显示:
094d9179d4d95960331573de08c1193c.png
编辑面板中的断点。当在断点处暂停时,在调试面板中显示应用的状态。this 变量展开并显示其值。

你可以 step in/out/over Dart 语句、热重载和恢复执行应用、以及像使用其他调试器一样来使用 Dart 调试器。 5: Debug 按钮切换调试面板的显示。

1.2 Flutter inspector

Flutter 插件提供了另外两个可能给你提供帮助的功能。Flutter inspector 是一个用来可视化以及查看 Flutter widget 树的工具,并帮助你:

  • 了解现有布局
  • 诊断布局问题

你可以使用 Android Studio 窗口右侧的垂直按钮切换检查器的显示。

3dcb192265888744ee93b5d24fa29266.png

1.3 Flutter outline

Flutter Outline 以可视形式显示构建方法。注意在构建方法上可能与 widget 树不同。你可以使用 Android Studio 窗口右侧的垂直按钮切换 outline 的显示。

df4b3e16c92e9aff53c701a18ad57f30.png

这篇指南剩下的部分介绍了如何搭建原生代码的调试环境。你应该可以想象到,对于 iOS 和

Android 这个过程是不同的。

小提示

通过安装 Presentation Assistant 插件来成为 Android Studio 的专业用户。你可以打开 Preferences > Plugins > Browsing repositories… 并在搜索框中输入 Presen 来找到并安装这个插件。

当你安装并重启 Android Studio 之后,通过使用以下功能这个插件可以帮助你成为一个专业用户:

  • 显示你执行的任何操作的名字和 Windows/Linux/Mac 的快捷键。
  • 允许你搜索并找到可用的操作、设置、文档等等。
  • 允许你切换首选项,打开视图或者执行操作。
  • 允许你设置键盘快捷键。(无法在 Mac 上运行此功能?)

例如,尝试下这个:

  • 当焦点在编辑面板中时,输入 command-Shift-A(Mac)或者 shift-control-A(Windows 和 Linux)。该插件会同时显示「查找」面板并显示在所有三个平台上执行此操作的提示。
de6676a7a9559bf2cca7be2519a03528.png

Presentation assistant's Find panel

Presentation assistant 的「查找」面板

4cb0cecdd6d643ae93b349a565ed21c5.png

Presentation assistant's action hint for opening its Find panel on Mac, Windows and LinuxPresentation assistant 的在 Mac、Windows 和 Linux 上打开「查找」面板的操作提示。

输入 attach 显示以下内容:
f13747c699fb8569d7b7d20473176664.png
更新之后,你可以输入 Flutter 或者 Dart 来查看是否有新的可用的操作。

使用 Escape 隐藏 Presentation Assistant 的「查找」面板。

2. 使用 Android Gradle 调试(Android)

为了调试原生代码,你需要一个包含 Android 原生代码的应用。在本节中,你将学会如何连接两个调试器到你的应用:1)Dart 调试器,和 2)Android Gradle 调试器。

  • 创建一个基本的 Flutter 应用。
  • 替换 lib/main.dart 为来自 url_launcher 包的以下示例代码

添加 url_launcher 依赖到 pubspec 文件,并执行 flutter pub get:

点击调试按钮,来同时打开调试面板并启动应用。等待应用在设备上启动并在调试面板中显示 Connected。(第一次可能需要一分钟,但是之后的启动会变快。)

应用包含两个按钮:

1)Launch in browser 在你的手机默认浏览器中打开 flutter.io ,

2)Launch in app 在你的应用中打开 flutter.io。

021951cf98d34d9757bf49ec96321a20.png
  • 点击 Attach debugger to Android process 按钮()

小提示

如果这个按钮没有显示在 Projects 菜单栏上,确定你正在使用的是 Flutter 项目而不是 Flutter 插件。

从进程对话框中,你应该可以看到每一个设备的入口。选择 show all processes 来显示每个设备可用的进程。选择你想附加到的进程。在这个例子中是 Motorola Moto G 的 com.google.clickcount(或 com.company.app_name)进程。
ef50783d8fd120af17a3cdf910fafeeb.png
在调试面板中,你现在应该可以看到一个 Android Debugger 标签页。在项目面板,展开 app_name > android > app > src > main > java > io.flutter plugins。双击 GeneratedProjectRegistrant 在编辑面板中打开 Java 代码。

Dart 和原生调试器都在与同一个进程交互。使用其中一个或者同时使用两个来设置断点、检查堆栈、恢复运行…… 换句话说,调试!

b2f195d97da277c98f593481745743d5.png

Dart 调试面板和 lib/main.dart 中的两个断点。

05be1a98c2d3be7a817ca05ecaed8df7.png
  • 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、付费专栏及课程。

余额充值