检查页面布局
======

inspector用于检查页面布局，通过双向定位功能帮助开发者在DevEco Studio中快速定位组件、修改属性和调试组件，以提高开发效率。

ArkUI获取当前显示页面中所有组件的信息，包括组件树的父子结构、尺寸、位置、样式、属性和状态。获取组件树信息后，生成并展示为Inspector组件树。DevEco Studio的使用具体可以参考[Inspector调试能力](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ui-inspector-profiler#inspector调试能力)。

inspector针对UI组件的布局或绘制送显完成，还提供了注册与取消监听函数的C API接口，具体使用可以参考[添加事件监听](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ndk-add-component-events)。

#### 使用约束

1.  不支持动效类组件的控件树实时刷新功能。
    
2.  支持获取组件的属性和样式，但不支持获取controller和Builder对象。
    
3.  不支持获取组件的方法、事件。
    

#### UIContext查询组件树和组件信息能力

ArkUI提供@ohos.arkui.UIContext([UIContext](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-uicontext))扩展能力，通过[getFilteredInspectorTree](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-uicontext#getfilteredinspectortree12)获取组件树及组件属性，通过[getFilteredInspectorTreeById](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-uicontext#getfilteredinspectortreebyid12)获取指定的组件及其子组件的属性。支持设置过滤条件进行查询。

下述示例，展示了getFilteredInspectorTree和getFilteredInspectorTreeById的基本用法。

import { UIContext } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Entry
@Component
struct ComponentPage {
  loopConsole(inspectorStr: string, i: string) {
    hilog.info(0x0000, \`InsTree ${i}| type: ${JSON.parse(inspectorStr).$type}, ID: ${JSON.parse(inspectorStr).$ID}\`,
      'InsTree');
    if (JSON.parse(inspectorStr).$children) {
      i += '-';
      for (let index = 0; index < JSON.parse(inspectorStr).$children.length; index++) {
        this.loopConsole(JSON.stringify(JSON.parse(inspectorStr).$children\[index\]), i);
      }
    }
  }

  build() {
    Column() {
      Text('Hello World')
        .fontSize(20)
        .id('TEXT')
      Button('content').onClick(() => {
        const uiContext: UIContext = this.getUIContext();
        let inspectorStr = uiContext.getFilteredInspectorTree(\['content'\]);
        hilog.info(0x0000,\`InsTree : ${inspectorStr}\`, 'InsTree');
        inspectorStr = JSON.stringify(JSON.parse(inspectorStr));
        this.loopConsole(inspectorStr, '-');
      })
      Button('isLayoutInspector').onClick(() => {
        const uiContext: UIContext = this.getUIContext();
        let inspectorStr = uiContext.getFilteredInspectorTree(\['isLayoutInspector'\]);
        hilog.info(0x0000,\`InsTree : ${inspectorStr}\`, 'InsTree');
        inspectorStr = JSON.stringify(JSON.parse(inspectorStr).content);
        this.loopConsole(inspectorStr, '-');
      })
      Button('getFilteredInspectorTreeById').onClick(() => {
        const uiContext: UIContext = this.getUIContext();
        try {
          let inspectorStr = uiContext.getFilteredInspectorTreeById('TEXT', 1, \['id', 'src'\]);
          hilog.info(0x0000,\`result1: ${inspectorStr}\`, 'result1');
          inspectorStr = JSON.stringify(JSON.parse(inspectorStr)\['$children'\]\[0\]);
          hilog.info(0x0000,\`result2: ${inspectorStr}\`, 'result2');
          inspectorStr = uiContext.getFilteredInspectorTreeById('TEXT', 1, \['src'\]);
          inspectorStr = JSON.stringify(JSON.parse(inspectorStr)\['$children'\]\[0\]);
          hilog.info(0x0000,\`result3: ${inspectorStr}\`, 'result13');
        } catch (e) {
          hilog.error(0x0000, \`getFilteredInspectorTreeById error: ${e}\`, 'error');
        }
      })

    }
    .width('100%')
    .height('100%')
  }
}

#### 布局回调

通过[@ohos.arkui.inspector (布局回调)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-arkui-inspector)提供注册组件布局和组件绘制完成的回调通知能力。

下述示例，展示了布局回调的基本用法。

import { inspector } from '@kit.ArkUI';

@Entry
@Component
struct ImageExample {
  build() {
    Column() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
        Row({ space: 5 }) {
          // 请将$r('app.media.startIcon')替换为实际资源文件
          Image($r('app.media.startIcon'))
            .width(110)
            .height(110)
            .border({ width: 1 })
            .id('IMAGE\_ID')
        }
        .id('ROW\_ID')
      }
    }.height(320).width(360).padding({ right: 10, top: 10 })
  }

  listenerForImage: inspector.ComponentObserver = this.getUIContext().getUIInspector().createComponentObserver('IMAGE\_ID');
  listenerForRow: inspector.ComponentObserver = this.getUIContext().getUIInspector().createComponentObserver('ROW\_ID');

  aboutToAppear() {
    let onLayoutComplete: () => void = (): void => {
      // 补充待实现的功能
    };
    let onDrawComplete: () => void = (): void => {
      // 补充待实现的功能
    };
    let onDrawChildrenComplete: () => void = (): void => {
      // 补充待实现的功能
    };
    let funcLayout = onLayoutComplete; // 绑定当前js对象
    let funcDraw = onDrawComplete; // 绑定当前js对象
    let funcDrawChildren = onDrawChildrenComplete; // 绑定当前js对象
    let offFuncLayout = onLayoutComplete; // 绑定当前js对象
    let offFuncDraw = onDrawComplete; // 绑定当前js对象
    let offFuncDrawChildren = onDrawChildrenComplete; // 绑定当前js对象

    this.listenerForImage.on('layout', funcLayout);
    this.listenerForImage.on('draw', funcDraw);
    this.listenerForRow.on('drawChildren', funcDrawChildren);

    // 通过句柄向对应的查询条件取消注册回调，由开发者自行决定在何时调用。
    // this.listenerForImage.off('layout', offFuncLayout)
    // this.listenerForImage.off('draw', offFuncDraw)
    // this.listenerForRow.off('drawChildren', offFuncDrawChildren)
  }
}

#### 组件标识属性的扩展能力

通过getInspectorByKey、getInspectorTree、sendEventByKey提供组件标识属性扩展能力，具体如下：

*   [getInspectorByKey](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-component-id#getinspectorbykey9)，获取指定id的组件的所有属性。
*   [getInspectorTree](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-component-id#getinspectortree9)，获取组件树及组件属性。
*   [sendEventByKey](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-component-id#sendeventbykey9)，给指定id的组件发送事件。

下述示例，展示了getInspectorByKey、getInspectorTree和sendEventByKey的基本用法。

@Entry
@Component
struct ComponentPage {
  build() {
    Column() {
      Text('Hello World')
        .fontSize(20)
        .id('TEXT')
        .onClick(() => {
          hilog.info(0x0000,\`Text is clicked\`, 'isClicked');
        })
      Button('getInspectorByKey').onClick(() => {
        let result = getInspectorByKey('TEXT');
        hilog.info(0x0000,\`result is ${result}\`, 'result');
      })
      Button('getInspectorTree').onClick(() => {
        let result = getInspectorTree();
        hilog.info(0x0000,\`result is ${JSON.stringify(result)}\`, 'result');
      })
      Button('sendEventByKey').onClick(() => {
        sendEventByKey('TEXT', 10, '');
      })
    }
    .width('100%')
    .height('100%')
  }
}