批量处理图片时,我希望用户能随时确认选中的图片和输出参数。手机屏幕窄,图片队列和设置适合上下排。到了电脑宽屏,队列和参数可以同时看,改完格式或尺寸就能确认当前处理的是哪一批图。

像素匠图片工坊是一款用 ArkTS 和 ArkUI 开发的本地图片处理工具。这次以工作台的批量处理为例,选三张内置示例图,设置为 JPEG、等比缩放 50%,然后查看结果和导出副本。手机和电脑使用同一套处理逻辑,页面按窗口宽度调整布局。

同一批图片在手机和电脑上怎么摆

手机上,选图摘要、图片队列、输出方案按顺序排列。用户先确认队列,再向下滚动调整参数。底部操作区显示本批输出摘要和「开始处理」按钮,长队列也能保留明确的下一步。

img

宽屏工作台把队列放在左侧,把输出方案和结果区域放在右侧。调整参数时,用户可以同时看到队列里的文件和尺寸。底部沿用同样的批处理操作区。

img

用窗口宽度切换单列和双栏

工作台把两个区域放进一个 12 列的 GridRow,用 BreakpointsReference.WindowSize 以应用窗口为断点参照。这里选了 840vp。窄屏区间里的两个 GridCol 各占 12 列,按顺序换行。窗口进入宽屏区间后,各占 6 列,刚好并排放下队列和参数。 ArkUI GridRow 文档 · ArkUI GridCol 文档

下面截取工作台的布局骨架,两个列容器里沿用原有的队列和设置组件。

GridRow({
  columns: 12,
  gutter: { x: 14, y: 14 },
  breakpoints: {
    value: ['840vp'],
    reference: BreakpointsReference.WindowSize
  }
}) {
  GridCol({ span: { xs: 12, sm: 6 } }) {
    // 图片队列和每张图片的处理状态
  }
  GridCol({ span: { xs: 12, sm: 6 } }) {
    // 输出设置和处理结果
  }
}.width('100%')

840vp 是这个工作台的布局取值。两栏里有图片缩略图、文件名、尺寸信息和参数控件,宽度够用时并排查看更方便。窗口较窄时,整行宽度留给一个区域,文件名和表单控件都有更充足的空间。工作台的内容区还设置了最大宽度,窗口继续放大时,页面内容保持在便于阅读和操作的范围内。

把主要操作放在滚动区外

布局调整后还有一个交互问题。队列变长,或者展开了更多输出选项时,用户仍需要能找到「开始处理」。批处理完成后,下一步则变成导出或发送结果。我的做法是把这些动作集中到 workspaceActionBar(),由页面外层 build() 在滚动内容之后渲染。

// homePage() 内部是可滚动的工作台内容。
// 以下是外层 build() 中挂载操作区的条件。
if (this.page === ProductPage.WORKSPACE && this.tasks.length > 0) {
  this.workspaceActionBar()
}

用户可以滚动查看队列和参数,操作区始终留在下面。处理前显示输出摘要和开始按钮,处理中切换为进度与停止动作,完成后展示导出入口。双栏和单列都读取同一份批处理状态,所以用户在两种布局里能找到对应的下一步。

两种布局共用一套图片处理流程

工作台从已选图片生成任务列表,开始处理后调用 ImageProcessor.processAll()。处理服务按队列逐张处理,进度回调把当前图片的任务快照写回列表。页面用同一份列表渲染文件名、处理进度、结果大小和失败状态。

下面是工作台调用处理服务的代码节选。进度回调更新对应的任务,并替换列表引用,让页面显示最新状态。

this.summary = await ImageProcessor.processAll(
  this.context(), this.tasks, this.options(), this.cancelSignal,
  (index: number, updated: ImageTask): void => {
    this.tasks[index] = updated.snapshot();
    this.tasks = [...this.tasks];
  }
);

处理完成后,应用先在本地生成副本,再由用户通过系统保存面板选择导出位置。这一步有自己的交互状态,接下来遇到的一个问题就出在这里。

关闭保存面板后,结果还能继续导出

早期真机回归时遇到过一个问题。三张图已经处理完成,打开系统保存面板后点取消,应用却把它计成三张导出失败。对用户来说,关闭面板只表示这次没有选保存位置,刚处理完的结果还应该留着。

修复时把空目标列表作为独立的取消结果。ExportResult.forSelection() 根据目标数量设置 canceled,保存服务在真正写文件之前处理这一分支。

const targetUris = await documentPicker.save(saveOptions);
const result = ExportResult.forSelection(targetUris.length);
if (result.canceled) return result;

工作台接到取消结果后显示「已取消导出,处理结果仍保留」。页面退出这次导出流程时,通过 finally 把 isExporting 恢复为 false,按钮重新可用。修复后的真机复验里,关闭保存面板后可以再次点导出,前面生成的副本仍在。

三张示例图的运行结果

下面的结果来自华为畅享 90 真机上的像素匠 3.0.0。选中三张内置示例图,使用 JPEG 和 50% 等比缩放,三张均处理成功。结果页显示这一批输入合计 7.79 MB,输出合计 247 KB。这个数字对应图中的素材和参数。

img

这批样例也可以留作布局回归。用同一组参数分别检查手机和宽屏工作台,记录队列的排列方式、主操作是否可触达,以及关闭保存面板后能否继续导出。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐