# 自定义教具与样式 (/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/custom-tools)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />
适用于 **Whiteboard Android SDK 2.16.134**，内嵌 **Appliance Plugin 1.1.45**。本章的 `Version` 条件指插件版本。

教具配置分为两类：通过教具状态设置当前用户的绘图样式，通过 `appliancePluginOptions.extras` 设置本地插件的样式与交互选项。先按[插件介绍](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/overview)完成启用，再在入房前填写插件选项。

## Selector 与属性栏 [#selector-与属性栏]

```java
import com.herewhite.sdk.domain.Appliance;
import com.herewhite.sdk.domain.MemberState;

// 入房前开启内置属性栏。
params.setUsingFloatBar(true);
// 入房成功后切换选择工具。
MemberState selector = new MemberState();
selector.setCurrentApplianceName(Appliance.SELECTOR);
room.setMemberState(selector);
```

内置 Selector 提供选中、移动和缩放交互。单独选中一张未锁定、支持旋转的图片时可使用左下角旋转手柄。属性栏由本端本地显示，其元素属性修改通过房间同步。

插件 `extras.overwriteSelectorStyles` 支持以下选择框样式：

| 字段 | 作用 |
| --- | --- |
| `highlightBox` | 选择框外框 |
| `highlightBoxPoint` | 普通缩放控制点 |
| `highlightBoxPoints` | 按 LT/LC/LB/TC/RT/RC/RB/BC 方向覆盖控制点 |
| `highlightBoxPointDot` | 端点编辑控制点 |
| `highlightBoxLock` | 锁定图标 |

## Extras 配置 [#extras-配置]

```java
import java.util.HashMap;
import java.util.Map;
import com.herewhite.sdk.domain.AppliancePluginOptions;

Map<String, Object> box = new HashMap<>();
box.put("borderWidth", 2);
box.put("borderStyle", "dashed");
box.put("borderColor", "#1677ff");
Map<String, Object> selectorStyles = new HashMap<>();
selectorStyles.put("highlightBox", box);

Map<String, Object> dotted = new HashMap<>();
dotted.put("lineCap", "round");
dotted.put("segment", 1);
dotted.put("gap", 2);
Map<String, Object> extras = new HashMap<>();
extras.put("overwriteSelectorStyles", selectorStyles);
extras.put("dottedStroke", dotted);

AppliancePluginOptions pluginOptions = new AppliancePluginOptions();
pluginOptions.setExtras(extras);
params.setAppliancePluginOptions(pluginOptions);
```

`Map<String, Object>` 按相同字段名序列化到 `appliancePluginOptions.extras`，以上配置在入房前设置。短虚线配置在教具状态选择 `StrokeType.Dotted` 时使用。

插件画笔样式配置包括 `normalStroke`、`dottedStroke` 和 `longDottedStroke`。`lineCap` 为 `round` 或 `square`；虚线的 `segment/gap` 决定段长和间隔，间隔按笔宽换算。1.1.45 默认短虚线、长虚线均配置 `segment=1/gap=2`，端点为 `round`；业务可按需要分别覆盖。

## Pencil 与 Shape [#pencil-与-shape]

```java
import com.herewhite.sdk.domain.Appliance;
import com.herewhite.sdk.domain.MemberState;
import com.herewhite.sdk.domain.StrokeType;

MemberState dottedPencil = new MemberState();
dottedPencil.setCurrentApplianceName(Appliance.PENCIL);
dottedPencil.setStrokeType(StrokeType.Dotted);
dottedPencil.setStrokeColor(new int[]{32, 102, 255});
dottedPencil.setStrokeWidth(4);
dottedPencil.setStrokeOpacity(0.6);
room.setMemberState(dottedPencil);
```

`StrokeType.Normal/Stroke/Dotted/LongDotted` 对应实线、笔锋、短虚线和长虚线；`strokeOpacity` 为线条透明度。后续需要实线时显式恢复 `StrokeType.Normal`。

```java
import com.herewhite.sdk.domain.MemberState;
import com.herewhite.sdk.domain.ShapeType;

MemberState triangle = new MemberState();
triangle.setShapeType(ShapeType.Triangle);
triangle.setStrokeColor(new int[]{32, 102, 255});
triangle.setStrokeWidth(3);
triangle.setFillColor(new int[]{255, 220, 100});
triangle.setFillOpacity(0.4);
room.setMemberState(triangle);
```

本版 `ShapeType` 提供 `Triangle/Rhombus/Pentagram/SpeechBalloon`。填充色和透明度通过 `setFillColor/setFillOpacity` 设置。

## Native 教具状态字段 [#native-教具状态字段]

| 字段 | Android 配置方法 |
| --- | --- |
| 当前教具 | `MemberState.setCurrentApplianceName(...)` |
| 线条颜色、粗细 | `setStrokeColor(...)`、`setStrokeWidth(...)` |
| 线型、线条透明度 | `setStrokeType(...)`、`setStrokeOpacity(...)` |
| 图形类型 | `setShapeType(...)` |
| 填充颜色、透明度 | `setFillColor(...)`、`setFillOpacity(...)` |
| 文字颜色、字号 | `setTextColor(...)`、`setTextSize(...)` |
| 橡皮尺寸 | `setPencilEraserSize(...)`，本端字段范围为 1～3 |

将状态传给 `room.setMemberState(...)`。未设置的可选字段不会作为新值提交，业务切换工具时显式恢复需要重置的样式。

内嵌插件还读取 `autoShape` 等扩展字段。对于本版 `MemberState` 未内置的字段，可在业务中定义命名的子类，通过同一个 Native `room.setMemberState(...)` 提交；类定义、开启和关闭示例见 [Auto Shape](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/extended-features)。扩展字段需使用插件实际接受的名称和类型，并保留其 JSON 序列化字段。

## 自定义 Native 工具栏 [#自定义-native-工具栏]

应用可使用 Android View 或 Compose 编写教具切换和样式设置面板，调用以上 Native 方法；复制、删除、撤销和重做分别使用 `room.copy()`、`room.delete()`、`room.undo()` 和 `room.redo()`。

自定义工具栏通过 MemberState 控制当前用户的教具与样式；内置 Selector 和属性栏负责选中元素的交互。

完整签名见[客户端 API](/zh-CN/api-reference/whiteboard/whiteboard-sdk/android/overview)。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />
适用于 **Whiteboard iOS SDK 2.16.147**。先按[插件介绍](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/overview)启用插件，在入房成功后提交当前用户的教具状态。

```objc
WhiteMemberState *state = [WhiteMemberState new];
state.currentApplianceName = AppliancePencil;
state.strokeColor = @[@32, @102, @255];
state.strokeWidth = @4;
state.strokeOpacity = @0.8;
[room setMemberState:state];
```

| 字段 | 用途 |
| --- | --- |
| currentApplianceName | Selector/Pencil/Shape/Text 等教具切换 |
| strokeColor / strokeWidth / strokeOpacity | RGB 颜色、粗细、线条透明度 |
| shapeType / fillColor / fillOpacity | 图形类型、填充颜色和透明度 |
| textColor / textSize | 文字颜色和字号 |
| pencilEraserSize | 局部橡皮尺寸 |

`WhiteRoomConfig.appliancePluginOptions.extras` 支持插件已开放的可序列化配置，例如 `dottedStroke`、`longDottedStroke`、`normalStroke`、`textEditor`、`strokeWidth`、`pencilEraser`、`overwriteSelectorStyles`。在入房前设置：

```objc
WhiteAppliancePluginOptions *options = [WhiteAppliancePluginOptions new];
options.extras = @{
  @"useBackgroundThread": @YES,
  @"normalStroke": @{ @"lineCap": @"round" },
  @"dottedStroke": @{ @"lineCap": @"round", @"segment": @1, @"gap": @2 },
  @"overwriteSelectorStyles": @{
    @"highlightBox": @{ @"borderColor": @"#2066ff" },
    @"highlightBoxPoint": @{ @"backgroundColor": @"#ffffff" }
  }
};
roomConfig.appliancePluginOptions = options;
```

以上 Selector 样式作用于内嵌白板界面的选中框。应用可用 UIKit/SwiftUI 控制本端工具栏，并通过 `setMemberState:` 设置教具与样式；撤销、重做、复制、删除使用本端 WhiteRoom 的公开方法。

Auto Shape 可通过业务扩展模型传递，见[Auto Shape](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/extended-features)。完整签名见[客户端 API](/zh-CN/api-reference/whiteboard/whiteboard-sdk/ios/docs/headers/agora-interactive-whiteboard-objective-c-overview)。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />
适用于 **Appliance Plugin 1.1.45**。先完成[启用插件](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/overview)，下文 `plugin` 为 `AppliancePluginInstance`。

## 当前用户的教具状态 [#当前用户的教具状态]

使用插件导出的扩展 `MemberState`，通过 `plugin.setMemberState` 提交。此状态控制当前用户，和 SDK 基础 `MemberState` 的字段集合不同。

```typescript
import { ApplianceNames, EStrokeType, ShapeType, type MemberState } from '@netless/appliance-plugin';

const pencil: Partial<MemberState> = {
  currentApplianceName: ApplianceNames.pencil,
  strokeColor: [32, 102, 255], strokeWidth: 4,
  strokeType: EStrokeType.Dotted, strokeOpacity: 0.8
};
plugin.setMemberState(pencil);
plugin.setMemberState({
  currentApplianceName: ApplianceNames.shape, shapeType: ShapeType.Polygon,
  vertices: 6, fillColor: [240, 245, 255], fillOpacity: 0.4
});
```

`strokeColor`、`fillColor` 为 RGB 数组；透明度为 0～1。切换工具时按业务需要显式恢复线型、填充和 `autoShape` 等状态。

## ExtrasOptions 配置 [#extrasoptions-配置]

在初始化时传入 `options.extras`；Fastboard 对应 `enableAppliancePlugin.extras`。回调函数放在 adaptor，不放在 extras。

```typescript
import type { ExtrasOptions } from '@netless/appliance-plugin';

const extras: ExtrasOptions = {
  useWorker: 'auto',
  useSimple: true,
  useBackgroundThread: true,
  dottedStroke: { lineCap: 'round', segment: 1, gap: 2 },
  longDottedStroke: { lineCap: 'round', segment: 4, gap: 3 },
  normalStroke: { lineCap: 'round' },
  undoRedo: { maxStackLength: 20 },
  overwriteSelectorStyles: {
    highlightBox: { borderColor: '#2066ff' },
    highlightBoxPoint: { backgroundColor: '#ffffff' },
    highlightBoxPoints: { LT: { borderColor: '#2066ff' } }
  }
};
```

| 配置 | 用途 |
| --- | --- |
| useWorker / allowImageBitmapFallback / useSimple | Worker 选择和绘制模式；默认 auto、true、true |
| useBackgroundThread | 背景图能力，默认 false |
| pencilEraser / strokeWidth / bezier | 橡皮、笔宽和曲线处理 |
| textEditor | 文字编辑器样式和交互 |
| normalStroke / dottedStroke / longDottedStroke | 线型端点、长度和间隔 |
| overwriteSelectorStyles | 框选边框、控制点和锁定图标样式 |
| backgroundImageLoadOptions | 背景图超时与重试策略 |
| cursor | 插件光标配置 |
| undoRedo | 撤销重做配置；跨用户全局撤销默认关闭 |

## 自定义 Selector 与属性面板 [#自定义-selector-与属性面板]

通过 `getSelectedElements(viewId)` 获取快照；有效 View 未选中元素时仍返回快照，`selectedIds` 和 `selectedElements` 为空数组；没有可用 View 时可能返回 `undefined`。使用 `getFloatbarContainer(viewId)` 获得面板容器，外部容器定位可用 `getViewOffsetToContainer(container, viewId)`。

更新已选中元素使用 `updateSelectedElements(viewId, changes)`，复制和删除使用 `copySelectedElements(viewId)`、`deleteSelectedElements(viewId)`，清空选择使用 `blurSelector(viewId)`。这些操作返回 Promise，业务拒绝通常通过结果的 `ok=false` 和 `reason` 表示；应检查 `ok`，不要只依赖 `catch`。`blurSelector` 在拖动/缩放/旋转中可能返回失败结果。

`viewRect` 使用当前 View 的 DOM 视图坐标，不能直接当作世界坐标。修改属性前用 `isElementPropertySupported(toolsType, field)` 判断元素是否支持该属性。结果表示模型操作完成，不能泛化为资源或首帧就绪。

Selector 的四类事件为 `selectedElementsChange`、`selectorGeometryChange`、`selectorTransformChange`、`remoteSelectorChange`，分别表示选中集合、最终几何、交互过程、远端同步结果。监听及清理示例见[事件监听与元素查询](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/events-and-query#selector-事件)。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="harmonyos" />
适用于 **Whiteboard HarmonyOS SDK 0.2.11**，内嵌 **Appliance Plugin 1.1.45**。

通过 `MemberState` 设置当前用户的教具与绘图样式，通过 `WhiteboardOptions.appliancePluginOptions.extras` 配置本地插件。先按[教具插件介绍](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/overview)开启插件；组件创建前设置选项，入房成功后调用 `WhiteboardController`。

## Selector 与内置属性栏 [#selector-与内置属性栏]

```typescript
import { Appliance } from '@shengwang/whiteboard';

// 创建 Whiteboard 组件前配置。
options.floatBar = true;
// 入房成功后切换选择工具。
controller.setAppliance(Appliance.SELECTOR);
```

内置 Selector 提供选中、移动和缩放交互。单独选中一张未锁定、支持旋转的图片时，可使用左下角旋转手柄。属性栏在本端显示，元素属性修改通过房间同步。

## Extras 配置 [#extras-配置-1]

通过公开的 `AppliancePluginExtrasOptions` 配置文字编辑器与光标：

```typescript
import { AppliancePluginExtrasOptions } from '@shengwang/whiteboard';

const extras: AppliancePluginExtrasOptions = {
  textEditor: {
    showFloatBar: true,
    canSelectorSwitch: true,
    rightBoundBreak: true
  },
  cursor: { enable: true, expirationTime: 3000 }
};
options.appliancePluginOptions = { extras: extras };
```

`showFloatBar` 控制文字编辑属性栏，`canSelectorSwitch` 控制文字编辑时能否切换选择工具，`rightBoundBreak` 控制右边界换行。光标配置中的 `enable` 控制是否显示，`expirationTime` 为过期时间，单位毫秒。

已有其他 extras 配置时，将字段合并到同一个配置对象，避免后续赋值覆盖之前的设置。

## Pencil 与 Shape [#pencil-与-shape-1]

```typescript
import { Appliance, MemberState } from '@shengwang/whiteboard';

const pencil: MemberState = {
  currentApplianceName: Appliance.PENCIL,
  strokeColor: [32, 102, 255],
  strokeWidth: 4
};
controller.setMemberState(pencil);
```

`strokeColor` 使用 RGB 三元组，`strokeWidth` 设置线条粗细。

```typescript
import { Appliance, MemberState, ShapeType } from '@shengwang/whiteboard';

const triangle: MemberState = {
  currentApplianceName: Appliance.SHAPE,
  shapeType: ShapeType.TRIANGLE,
  strokeColor: [32, 102, 255],
  strokeWidth: 3
};
controller.setMemberState(triangle);
```

`ShapeType` 提供 `TRIANGLE/RHOMBUS/PENTAGRAM/SPEECH_BALLOON`，分别对应三角形、菱形、五角星和气泡框。

## 教具状态字段 [#教具状态字段]

| 字段 | 用途 |
| --- | --- |
| `currentApplianceName` | 当前教具 |
| `shapeType` | 图形类型 |
| `strokeColor`、`strokeWidth` | 线条 RGB 颜色与粗细 |
| `textColor`、`textSize` | 文字 RGB 颜色与字号 |

将状态传给 `controller.setMemberState(...)`。未设置的可选字段不会作为新值提交，业务切换工具时显式恢复需要重置的样式。

应用可使用 ArkUI 编写自己的教具按钮与样式面板，调用上述 Native 方法；复制、删除、撤销和重做分别使用 `controller.copy()`、`controller.deleteOperation()`、`controller.undo()` 和 `controller.redo()`。

单笔图形识别的业务扩展模型及开启/关闭示例见[Auto Shape](/zh-CN/realtime-media/whiteboard/whiteboard-sdk/build/appliance-plugin/extended-features)。完整签名见[客户端 API](/zh-CN/api-reference/whiteboard/whiteboard-sdk/harmonyos/overview)。
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>
