Flutter inspector工具初体验

925 阅读9分钟

一、这是什么?

Flutter widget inspector是一个强大的工具,用于可视化和查看widget树。Flutteer框架层使用widgets作为核心构建模块来处理空间(例如文本、按钮和切换等)到布局(例如居中、填充、行和列等)的所有内容。Flutter inspector不仅可以帮助你可视化查看Flutter widget树,还有其他的作用:

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

image.png

二、开始使用

要调试布局问题,请在Debug模式下运行应用程序,然后点击DevTools工具栏上的Flutter inspector选项打开调试面板。

2.1、可视化地调试布局问题

下面是Flutter inspector工具栏中可用功能指南。当空间有限时,将直接使用图标展示。

Select widget mode icon 选择 widget 模式:启用此按钮以在设备上选择wiidget进行查看。

Refresh tree icon 刷新树:重新加载当前widget的信息。

Slow animations icon 慢速动画:以五分之一的速度运行动画以便对它们进行优化。

Show guidelines mode icon 显示引导线:覆盖一层引导线以帮助调整布局问题。

Show baselines icon 显示基线:针对文字对齐展示文字的基线。对减产文字是否对齐有帮助。

Highlight repaints icon 高亮重绘制内容:重新绘制时在图层上依次显示不同的颜色。

Highlight oversized images icon 高亮尺寸过大的图片:在运行的应用程序中高亮并反转消耗过多内存的图像。

三、检查一个widget

你可以浏览widget树并查看其附近的widgets和它们的属性值。

要在widget树中找到单个UI元素,请单击工具栏中的Select Widget Mode按钮。这将使设备上的应用程序进入「widget select」模式。单击应用界面上的任何widget,将选中widget并将widget树滚动到对应的结对安。再次点击Select Widget Mode按钮则退出「widget select」模式。

在调试布局问题时,要查看的关键字段是sizeconstraints。其中约束沿树结构向下传递,尺寸信息则向上返回。

四、Flutter布局浏览器

Flutter布局浏览器可以帮助你更好地理解Flutter布局,可以参考一下我的另外一篇文章: Flutter之Layout Explorer初体验

4.1、使用布局浏览器

从Flutter Inspector中,选择一个widget。布局浏览器支持弹性布局和固定大小的布局,并且针对它们配备了特定的工具。

4.1.1、弹性布局

当你选择了一个弹性布局widget(例如,RowColumnFlex)或它的子widget时,弹性布局工具将显示在布局浏览器中。

布局浏览器会只管显示Flex widgets以及其子元素的布局方式。浏览器中还显示主轴和交叉轴,以及每个轴当前的对齐方式(例如,start、end和spaceBetween)。它还显示了诸如弹性系数、弹性是适配和布局约束等详细信息。

此外,浏览器中还会显示布局约束冲突和渲染溢出错误。正如你的设备上看到的那样,违背布局约束的地方会被标记红色,溢出错误已标准的「黄色条带」显示。这些可视化的错误是为了让我们更好地理解溢出错误发生的原因,并了解如何修复它们。

layout_explorer_errors_and_device.gif

Select Widget Mode模式下,点击布局浏览器中的widget会同步选择到设备上。启用此模式,请点击调试模版中的Select Widget Mode按钮。

image.png

你可以在布局浏览器的下拉列表修改属性值,例如弹性系数、弹性适配和对其方式。当修改widget的属性时,您会看到新的值的同时在浏览器和运行Flutteer应用程序的设备上生效。浏览器通过动画使更改的效果清晰可见。从布局浏览器中对widget属性的更改不会修改源代码,将在热重载时还原。

4.1.2交互属性

布局资源管理器支持修改mainAxisAlignmentcrossAxisAlignmentRlexparentData.flex.将来,我们可能会添加对其他属性的支持,例如mainAxisSizetextDirectionFlexPareentData.fit

  1. mainAxisAlignment

layout_explorer_main_axis_alignment.gif

支持属性:

  • MainAxisAlignment.start
  • MainAxisAlignment.end
  • MainAxisAlignment.center
  • MainAxisAlignment.spaceBetween
  • MainAxisAlignment.spaceAround
  • MainAxisAlignment.spaceEvenly
  1. crossAxisAlignment

layout_explorer_flex.gif

支持属性:

  • CrossAlignment.start
  • CrossAlignment.center
  • CrossAlignment.end
  • CrossAlignment.stretch
  1. FlexParentData.flex

layout_explorer_flex.gif

布局浏览器支持设置7种弹性因子(null、0、1、2、3、4、5),但从技术上讲,弹性widget子级的弹性因子可以是任何整数。

  1. Flexible.fit

layout_explorer_fit.gif

布局浏览器支持两种不同类型的FlexFit:loosetight

4.1.3、固定大小布局

当您选择一个固定大小的widget而不是弹性widget时,它的布局信息将显示在布局浏览器中。你可以看到所有widget及其最近的上一级RenderObject的大小、约束和填充信息。

image.png

五、调试视觉效果

Flutter Inspector提供了多种可视化方式调试应用的方式。以下是在Flutter DevTools中的inspector可用选项:

5.1、慢速动画

启用时,动画将以五分之一的原有速度运行,方便对视觉效果进行检测。当你想要仔细检查并调试看起来不正常的动画时,这个选项会非常有用。

你也可以使用代码设置:

import 'package:flutter/scheduler.dart';

void setSlowAnimations() {
    timeDilation = 5.0;
}

这会让动画时长增加5倍(倍速减慢5倍)。

下面的录屏展示了动画减速前后的对比。

debug-toggle-slow-animations-disabled.gif debug-toggle-slow-animations-enabled.gif

5.2、显示引导线

该功能会在您的应用顶层绘制引导线,展示绘制区域、对齐、间距、滚动视图、裁剪和空位填充。

这个工具能帮助你更加了解你的布局。例如查找不需要的填充或理解widget的对齐方式。

你也可以通过代码启用:

import 'package:flutter/rendering.dart';

void showLayoutGuidelines() {
    debugPaintSizeEnable = true;
}

5.2.1、Render boxes

RenderBox

绘制在屏幕上的widgets会创建一个RenderBox,它是Flutter布局的基础构建。这些RenderBox会加上一个浅蓝色的边框。

image.png

5.2.2、对齐方式

对齐方式将黄色箭头展示。这些箭头会显示出垂直和竖屏方向的widget相对其付布局的偏移。例如,这各个按钮图标有四个箭头表示它被居中展示:

image.png

5.2.3、间距

间距会以半透明的蓝色背景显示:

image.png

5.2.4、滚动视图

包含滚动内容的widget(例如ListView)会展示绿色的箭头:

image.png

5.2.5、裁剪

使用了诸如ClipRect Widget进行裁剪的内容,会以粉红色的虚线加一个剪刀图标展示:

image.png

5.2.6、空位填充

空位填充的widgets会以灰色背景展示,例如没有child的SizedBox:

image.png

5.3、显示基线

该选项会显示所有的基线。基线是水平的用来定位文字的线。

在检查文字是否垂直对齐时,基线会非常有用。例如,下图中文字的基线稍微有一些错位:

image.png

Baseline widget可以用来调整基线。

在设置了基线的RenderBox上 ,都会显示一条线。字母的基线是以绿色展示,而符号的基线以黄色展示。

你可以通过代码启用:

import 'package:flutter/rendering.dart';

void shoowBaselines() {
    debugPaintBasselinesEnabled = true;
}

5.4、高亮重绘制内容

该选项会为所有的RenderBox绘制一层边框,在它们重新绘制时改变颜色。

以彩虹色谱循环的颜色,有利于你找到应用中频繁重绘导致性能消耗过大的部分。

例如,一个动画可能导致整个页面一直在重绘。将动画使用RepaintBoundary widget嵌套,可以保证动画只会导致其本身重绘。

下面是一个进度指示器导致其容器重绘的例子:

class EverythingRepaintsPage extends StatelessWidget {
    const EverythingRepaintsPage({super.key});
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: const Text('Repaint Example')),
            body: const Center(
                child: CircularProgressIndicator(),
            ),
        );
    }
}

debug-toggle-guidelines-repaint-1.gif

将进度指示器使用RepaintBoundary包裹,可以将重绘范围缩小范围至它本身占有的区域。

class AreaRepaintsPage extends StatelessWidget {
    const AreaRepaintsPage({super.key});
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: const Text('Repaint Example'),
            body: const Center(
              child: RepaintBoundary(
                  child: CircularProgressIndicator(),
              ),  
            ),
        );
    }
}

debug-toggle-guidelines-repaint-2.gif

RepaintBoundary widget也有一些额外的消耗。它们对性能有一定的帮助,但也会在创建额外的绘制画布时增加一定的内存消耗。

你也可以通过代码启用:

import 'package:flutter/rendering.dart':

void highlightRepaints() {
    debugRepaintRainbowEnable = true;
}

5.5、高亮尺寸过大的图片

该选项会将尺寸过大的图片高亮表示,并且进行垂直翻转及色调反转:

image.png

被高亮的图片使用了过多的内存。例如一张5MB大小的图片以100x100像素展示。

这样的图片会导致性能低下,在低端设备上尤为明显,而当你在诸如列表中有大量这样的图片时,性能的下降会叠加。调试控制台窗口会打印每个图片的信息:

     dash.png has a display size of 213×392 but a decode size of 2130×392, which uses an additional 2542KB.

超过128KB的图片被视为过大。

5.5.1、调整图片

在可能的情况下,最好的办法是调整图片资源的大小,让它变得更小。

如果该方法不可行,你可以使用Image构造里的cacheHeightcacheWidth参数:

class ResizedImage extends StatelessWidget {
    const ResizedImage({super.key});
    
    @override
    Widget build(BuildContext context) {
        return Image.asset(
            'dash.png',
            cacheHeight: 213,
            cacheWidth: 392,
        );
    }
}

这样的方法可以让引擎以指定的大小解析图片,减少内存的消耗(解析开销和空间占有相较图片调整图片本身仍然较大)。无论任何设置参数,图片依然会以布局限制或大小进行渲染。

该属性同样可以使用代码设置:

void showOversizedImages() {
    debugInvertOversizedImages = true;
}

六、树的详细信息

选择Details Tree标签展示选中widget的树结构的详细信息。

image.png

从树的详细信息中,你可以获取有关widget的属性、渲染对象和子节点等有用信息。

image.png

七、追踪widget创建

Flutter Inspector的部分功能是基于检测应用程序的源码,以便更好地理解创建widget的源位置。FLutter inspector可以以类似于源代码中定义UI的方式呈现widget数。如果没有它,widget树中的组成某个节点的树结构会更深,并且更难理解运行时widget的层次构建如何与应用程序的UI相对应。

你可以通过在flutter run后面添加参数-no track widget creation来禁用此功能。

下面是widget树在启用和不启用追踪widget创建下的示例。

启用追踪widget创建(默认):

image.png

关闭追踪widget创建(不推荐):

image.png

此功能可避免在调试构建中将其他相同的const的Widgets视为相同。