鸿蒙 HarmonyOS 6 | Pura X Max 鸿蒙原生适配 17:图片预览页增加右侧信息面板 原创
头像 小雨同学 2026-06-01 08:41:29    发布
0 浏览 0 点赞 0 收藏

前言

我在处理 OCR 原图查看页时,最先感到别扭的是反复切换。用户拍完一张通知、票据或者会议照片以后,通常会做两件事:一边确认原图是否清晰,一边核对识别结果是否可信。外屏状态下,图片和识别结果通过按钮切换还能接受,因为窗口宽度有限,用户一次重点处理一个区域,页面关系也比较容易理解。

到了 Pura X Max 展开态以后,这个页面继续沿用上下切换就有点浪费空间。左侧完全可以展示原图预览,右侧承接识别结果、结构化摘要和操作按钮。用户对照原图确认识别文本时,不需要在两个页面区域之间反复跳转,也不需要一会儿滑到上方观察原图,一会儿滑到下方核对识别内容。

图片预览页经常出现在这些场景里:

  • OCR 原图查看
  • 拍照确认页
  • 票据识别结果页
  • 通知截图整理页
  • 会议白板拍照整理页
  • 资料扫描后的文字校对页

这些页面的共同特点是,原始内容和整理结果之间存在对应关系,用户真正要完成的是对照、确认和处理。外屏只能通过切换按钮承接这个动作,而展开态已经有了并排展示的空间,页面结构就可以从单区域切换调整为左侧预览 + 右侧信息

Pura X Max 的尺寸变化足够让图片预览页改变组织方式,但左右分栏也需要边界。图片区域要保留最小展示宽度,右侧识别面板要有固定宽度,中间还要预留间距。如果遇到空间不足,页面需要继续退回原图和识别结果的切换结构。

我这里用占位图形模拟原图区域,不依赖本地图片资源。这样放到 Index.ets 后就能直接运行,重点观察图片预览区和右侧识别面板在不同宽度下的布局变化。

一、原来切换方式的问题

1.1 外屏仍然适合切换

外屏下,我一般会把图片预览和识别结果处理成两个状态。顶部放一个分段按钮,用户可以在原图和识别结果之间切换。这个结构对窄窗口比较实用,因为图片本身需要高度,识别结果也需要阅读空间,左右同时展示会让两边都被压缩。

最早的结构大概会写成这样:

if (this.activePane === 'image') {  this.PreviewPanel()} else {  this.ResultPanel()}

这个写法没有复杂的布局判断,状态也容易维护。外屏里用户点击识别结果,页面切到文本和操作按钮;再点击原图,页面回到图片预览。这个过程多了一次切换,但小屏里很难长期展示两块内容,保留切换按钮更符合外屏的空间条件。

在拍照确认、票据识别、短通知整理这些场景里,外屏上下切换可以继续保留。用户通常只是确认一次原图,再确认一次识别结果,切换成本还在可接受范围内。真正让我重新调整结构的,是展开态下仍然要求用户在两块内容之间来回切换。

1.2 但展开态会拖慢校对

我把图片预览页切到展开态后,最先观察到的是横向空间没有参与页面组织。用户查看原图时,识别结果被隐藏;用户查看识别结果时,原图又离开当前视野。遇到识别错误时,用户要重新回到原图确认,再切换回识别结果继续处理。

OCR 页面很依赖对照关系。比如原图里有日期、金额、地点,识别结果里也提取了这些字段。用户校对时需要反复确认字段和原图之间的对应关系。两块内容无法同时展示时,校对过程会变成观察原图、记住内容、切换结果、继续核对。这个过程在短文本里还能接受,遇到票据、通知、白板照片时就会让人频繁中断。

所以,在展开态里,我会把图片预览页拆成两个明确区域:

  • 左侧承接原图预览,尽量保留足够大的可视区域。
  • 右侧承接识别结果、结构化摘要和操作按钮。
  • 窄窗口继续使用原图和结果的切换按钮。
  • 宽窗口满足最小宽度后,再进入左图右信息结构。

二、图片区要保留最小宽度

2.1 左侧预览不能被压缩

展开态下增加右侧面板时,我不会只用一个宽度阈值决定分栏。图片预览页有一个很实际的前提:左侧图片区必须足够大。右侧识别面板一出现,如果左侧原图只剩一条窄区域,用户仍然看不清原图细节,左右分栏就失去了校对价值。

我给图片预览区设置了最小宽度,右侧面板固定为 320vp,中间间距为 16vp。页面进入分栏前,会先计算当前可用宽度能否放下这些区域。

private readonly previewMinWidth: number = 520;private readonly resultPanelWidth: number = 320;private readonly twoColumnGap: number = 16;

这三个值可以根据真实页面继续调整。票据类图片需要展示更多细节,左侧宽度可以继续提高;右侧只展示少量识别字段时,面板宽度可以收缩到 300vp 左右;右侧如果需要加入编辑按钮、校对状态和处理建议,就要把面板宽度提升到 340vp 或 380vp。

我会优先保住图片区。OCR 校对的前提是用户能看清原图,如果左侧预览被压缩得太厉害,右侧识别结果再完整也很难核对。这个判断和普通详情页不一样,图片预览页里的原图可读性直接决定页面结构是否成立。

2.2 宽度计算放在页面层

示例里的判断集中在 canUseSplit() 中。

private canUseSplit(): boolean {  const width = this.getEffectiveWidth();  const availableWidth = width - this.getPagePadding() * 2;  const requiredWidth = this.previewMinWidth + this.resultPanelWidth + this.twoColumnGap;​  return width >= this.expandedThreshold && availableWidth >= requiredWidth;}

这里会先扣掉页面左右 padding,再比较图片区、结果面板和中间间距的总宽度。这样可以避免一个常见情况,窗口看起来已经很宽,实际加上边距和右侧面板后,左侧图片区仍然被压缩。

我会把这个判断放在页面层。图片预览组件只负责展示原图,右侧面板只负责展示识别结果。是否进入左右分栏,由页面统一判断。后面调整右侧面板宽度,或者给图片区提高最小宽度时,不需要在两个组件里重复修改判断。

三、右侧面板承接校对内容

3.1 识别结果贴近原图展示

图片预览页里的右侧面板,我会把它当成校对区。它负责展示识别文本、结构化摘要和当前操作,让用户观察左侧原图时,右侧可以直接确认提取结果。发现识别错误时,用户不用离开当前页面,也不用重新切换区域。

示例里右侧包含三类内容:

  • 识别文本行
  • 结构化摘要
  • 保存、重新识别、复制结果等按钮

这些内容都和原图校对有关,不会把右侧面板改造成完整详情页。右侧继续加入历史记录、附件、长说明和复杂表单时,用户会在面板里重新寻找重点,左图右信息的价值也会被削弱。

我会把右侧面板控制成结果确认区。它的任务是帮助用户判断识别内容是否可用,然后完成保存或重新识别。复杂编辑可以进入独立页面,右侧面板只承接当前校对动作。

3.2 小屏状态仍然使用切换按钮

小屏下,右侧面板没有足够空间展示,页面继续通过原图 / 识别结果按钮切换。这个状态下,用户一次只处理一块内容。为了让切换过程保留上下文,activePane 放在页面层。

@State private activePane: string = 'image';

点击原图或识别结果只改变展示区域,不会重置识别结果,也不会影响保存状态。等窗口宽度满足分栏条件后,页面进入左右结构,activePane 不再决定主布局,但这个状态仍然保留,方便窗口缩回小屏时继续使用。

这种状态处理很适合 OCR 页面。用户可能在外屏里先查看识别结果,再展开设备继续对照原图;也可能在展开态里保存结果后,又缩回外屏继续处理。布局形态可以切换,识别结果和操作状态不能跟着丢。

四、运行页面验证差异

为了观察这个结构,我把页面压缩成一个独立示例。示例不依赖真实图片文件,左侧原图区域通过占位图形模拟通知截图,里面放了标题、金额、日期和地点等文字块;右侧识别面板展示对应识别行和结构化摘要。这样在模拟器里不需要准备图片资源,也能验证页面结构。

外屏状态下,页面顶部有原图和识别结果切换按钮。当前显示原图时,页面只展示图片预览区域;切到识别结果后,页面展示识别文本和操作按钮。

展开态状态下,页面进入左图右信息结构。左侧原图保持较大的展示区域,右侧识别结果固定显示。用户可以一边观察原图上的文字块,一边核对右侧识别结果。

五、实际项目中怎么处理

5.1 占位图替换成真实图片组件

示例里没有使用真实图片资源,而是通过 ArkUI 组件模拟原图区域。迁回真实项目时,可以把 PreviewPlaceholder() 替换成真实图片展示组件,图片来源可以是相册、拍照后的沙箱路径、OCR 原图路径或者处理后的压缩图。

真实图片预览还要继续处理缩放、长图、旋转和清晰度。如果是票据、通知、白板这类图片,用户可能需要放大观察局部文字。示例里的占位图只用于验证布局结构,真实项目里还需要补充图片缩放、双击查看、局部放大和查看原图等交互。

5.2 图片和识别结果使用同一份数据

图片预览和识别结果属于同一条记录的两个视角。真实项目里,不建议图片区域维护一套状态,识别结果区域再维护一套状态。可以把当前材料、图片路径、识别文本、结构化摘要和保存状态都放在页面层或数据服务层,再让图片区域和右侧面板分别读取这份数据。

这样窗口从外屏切到展开态时,页面不会重新识别,也不会丢掉用户刚刚修改过的结果。图片和识别结果只是同一条记录的不同展示区域,布局可以切换,数据不要拆成两份。

5.3 右侧面板控制在轻量校对范围

右侧面板适合放识别结果和轻量操作。比如保存结果、重新识别、复制文本、加入待办,这些动作都适合放在右侧。复杂校对、逐字段编辑、长文本修订、图片裁剪,最好进入完整页面。

如果右侧面板继续增加内容,左侧原图也会被挤压,用户反而看不清预览。图片预览页需要保留原图和识别结果之间的对照关系。右侧面板完成校对和处理动作就够了,完整编辑流程可以交给详情页或专门的编辑页。

总结

图片预览页在 Pura X Max 展开态里,可以把原图和识别结果放到同一屏。外屏下继续使用原图 / 识别结果切换,避免左右区域互相挤压;展开态里使用左图右信息结构,让用户可以直接对照原图和识别文本,减少区域切换带来的中断。

我后面处理这类 OCR 预览页时,会先确认几件事:

  • 原图区域要有最小宽度,避免被右侧面板压缩到看不清。
  • 识别结果适合在右侧展示,方便用户对照原图。
  • 小屏继续使用切换按钮,不强行左右分栏。
  • 右侧只放识别文本、摘要和轻量操作,复杂编辑进入独立页面。
  • 图片路径、识别结果和保存状态放在同一套数据里,布局切换时继续保留。

放到实际项目里,占位图要替换成真实图片组件,右侧识别面板要接入 OCR 结果和结构化摘要。页面真正要保留的是原图和结果之间的对照关系。窗口宽度足够时,让它们并排出现;窗口宽度不足时,继续使用上下切换,让用户一次处理一个区域。

完整代码

interface RecognitionLine {  id: number;  label: string;  text: string;  confidence: string;}​interface SummaryItem {  id: number;  label: string;  value: string;}​@Entry@Componentstruct Index {  // 页面真实宽度,由 onAreaChange 写入  @State private pageWidth: number = 0;​  // 演示宽度覆盖真实窗口宽度,方便在同一台模拟器里观察外屏和展开态  @State private previewWidth: number = 0;​  // 小屏状态下用于切换原图和识别结果  @State private activePane: string = 'image';​  // 模拟保存次数,用来验证布局切换后操作状态是否保留  @State private saveCount: number = 0;​  private readonly expandedThreshold: number = 860;  private readonly previewMinWidth: number = 520;  private readonly resultPanelWidth: number = 320;  private readonly twoColumnGap: number = 16;​  private readonly recognitionLines: RecognitionLine[] = [    {      id: 1,      label: '标题',      text: '社区物业缴费提醒',      confidence: '98%'    },    {      id: 2,      label: '金额',      text: '¥ 680.00',      confidence: '96%'    },    {      id: 3,      label: '截止日期',      text: '2026 年 5 月 28 日',      confidence: '97%'    },    {      id: 4,      label: '地点',      text: '社区物业服务中心一楼',      confidence: '92%'    }  ];​  private readonly summaryItems: SummaryItem[] = [    {      id: 1,      label: '材料类型',      value: '缴费通知'    },    {      id: 2,      label: '建议动作',      value: '保存为待办提醒'    },    {      id: 3,      label: '来源',      value: '拍照整理'    }  ];​  private getEffectiveWidth(): number {    if (this.previewWidth > 0) {      return this.previewWidth;    }​    return this.pageWidth;  }​  private getPagePadding(): number {    if (this.getEffectiveWidth() >= this.expandedThreshold) {      return 24;    }​    return 16;  }​  // 分栏前先确认左侧图片区、右侧识别面板和中间间距都能放下  private canUseSplit(): boolean {    const width = this.getEffectiveWidth();    const availableWidth = width - this.getPagePadding() * 2;    const requiredWidth = this.previewMinWidth + this.resultPanelWidth + this.twoColumnGap;​    return width >= this.expandedThreshold && availableWidth >= requiredWidth;  }​  private isExpanded(): boolean {    return this.canUseSplit();  }​  private getContentWidth(): Length {    if (this.previewWidth > 0) {      return this.previewWidth;    }​    return '100%';  }​  private getTitleSize(): number {    return this.isExpanded() ? 28 : 23;  }​  private getModeText(): string {    return this.isExpanded() ? 'expanded · 左图右信息' : 'compact · 图片/结果切换';  }​  private getModeDesc(): string {    if (this.isExpanded()) {      return '展开态下原图展示在左侧,识别结果和操作区固定在右侧。';    }​    return '小屏下原图和识别结果通过按钮切换,避免左右区域互相挤压。';  }​  private setPreview(width: number) {    this.previewWidth = width;  }​  private saveResult() {    this.saveCount += 1;  }​  @Builder  private PreviewButton(text: string, width: number) {    Text(text)      .fontSize(12)      .fontColor(this.previewWidth === width ? '#FFFFFF' : '#2F8F83')      .textAlign(TextAlign.Center)      .padding({ left: 10, right: 10, top: 7, bottom: 7 })      .backgroundColor(this.previewWidth === width ? '#2F8F83' : '#E6F4F1')      .borderRadius(999)      .onClick(() => {        this.setPreview(width);      })  }​  @Builder  private PaneButton(text: string, key: string) {    Text(text)      .fontSize(13)      .fontColor(this.activePane === key ? '#FFFFFF' : '#2F8F83')      .textAlign(TextAlign.Center)      .layoutWeight(1)      .height(36)      .backgroundColor(this.activePane === key ? '#2F8F83' : '#E6F4F1')      .borderRadius(18)      .onClick(() => {        this.activePane = key;      })  }​  @Builder  private HeaderPanel() {    Column({ space: 10 }) {      Row({ space: 10 }) {        Column({ space: 4 }) {          Text('图片预览页增加右侧信息面板')            .fontSize(this.getTitleSize())            .fontWeight(FontWeight.Bold)            .fontColor('#111827')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })​          Text(this.getModeText())            .fontSize(14)            .fontColor('#2F8F83')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })        }        .layoutWeight(1)​        Text('窗口 ' + Math.round(this.pageWidth).toString() + 'vp')          .fontSize(12)          .fontColor('#374151')          .padding({ left: 10, right: 10, top: 6, bottom: 6 })          .backgroundColor('#FFFFFF')          .borderRadius(999)      }      .width('100%')​      Text('演示宽度:' + Math.round(this.getEffectiveWidth()).toString() + 'vp。' + this.getModeDesc())        .fontSize(14)        .fontColor('#6B7280')        .lineHeight(21)        .maxLines(2)        .textOverflow({ overflow: TextOverflow.Ellipsis })​      Row({ space: 8 }) {        this.PreviewButton('自动', 0)        this.PreviewButton('外屏', 430)        this.PreviewButton('展开态', 1040)      }      .width('100%')    }    .width('100%')  }​  @Builder  private FakeDocumentLine(text: string, width: Length, bgColor: string) {    Text(text)      .fontSize(13)      .fontColor('#374151')      .height(30)      .width(width)      .padding({ left: 10, right: 10 })      .backgroundColor(bgColor)      .borderRadius(8)      .maxLines(1)      .textOverflow({ overflow: TextOverflow.Ellipsis })  }​  @Builder  private FakeParagraphLine(width: Length) {    Rect()      .width(width)      .height(8)      .radiusWidth(4)      .radiusHeight(4)      .fill('#E5E7EB')  }​  @Builder  private FakeDocumentBody() {    Column({ space: 18 }) {      Text('社区物业缴费提醒')        .fontSize(24)        .fontWeight(FontWeight.Bold)        .fontColor('#111827')        .width('100%')        .textAlign(TextAlign.Center)​      Column({ space: 12 }) {        this.FakeDocumentLine('缴费金额:¥ 680.00', '78%', '#FFF7ED')        this.FakeDocumentLine('截止日期:2026 年 5 月 28 日', '92%', '#EFF6FF')        this.FakeDocumentLine('办理地点:社区物业服务中心一楼', '86%', '#F0FDF4')      }      .width('100%')      .alignItems(HorizontalAlign.Center)​      Column({ space: 10 }) {        Text('通知内容')          .fontSize(15)          .fontWeight(FontWeight.Medium)          .fontColor('#111827')​        this.FakeDocumentLine('请在截止日期前完成缴费。', '100%', '#F9FAFB')        this.FakeDocumentLine('逾期可能影响后续服务办理。', '88%', '#F9FAFB')        this.FakeDocumentLine('如已缴费,请忽略本提醒。', '72%', '#F9FAFB')​        Column({ space: 8 }) {          this.FakeParagraphLine('96%')          this.FakeParagraphLine('88%')          this.FakeParagraphLine('92%')          this.FakeParagraphLine('76%')          this.FakeParagraphLine('84%')          this.FakeParagraphLine('64%')        }        .width('100%')        .padding({ top: 4 })      }      .width('100%')      .padding(16)      .backgroundColor('#FFFFFF')      .borderRadius(18)      .border({ width: 1, color: '#E5E7EB' })​      Column({ space: 10 }) {        Text('底部说明')          .fontSize(15)          .fontWeight(FontWeight.Medium)          .fontColor('#111827')​        this.FakeDocumentLine('业务办理时间:工作日 09:00 - 17:30', '100%', '#F9FAFB')        this.FakeDocumentLine('咨询电话:物业服务中心前台', '86%', '#F9FAFB')        this.FakeDocumentLine('请携带业主卡或身份证件办理。', '92%', '#F9FAFB')      }      .width('100%')      .padding(16)      .backgroundColor('#FFFFFF')      .borderRadius(18)      .border({ width: 1, color: '#E5E7EB' })    }    .width('100%')    .padding(22)    .backgroundColor('#FDF7ED')    .borderRadius(24)    .border({ width: 1, color: '#F3E4C8' })  }​  @Builder  private PreviewPlaceholder() {    Column({ space: 14 }) {      Row() {        Text('OCR 原图占位')          .fontSize(16)          .fontWeight(FontWeight.Medium)          .fontColor('#111827')​        Blank()​        Text('可滑动预览')          .fontSize(12)          .fontColor('#2F8F83')          .padding({ left: 8, right: 8, top: 4, bottom: 4 })          .backgroundColor('#E6F4F1')          .borderRadius(999)      }      .width('100%')      .flexShrink(0)​      // 原图内容可能比可视区域更高,所以这里让原图区域自己滚动。      // 左右分栏时,左侧卡片不会再裁掉底部内容。      Scroll() {        Column() {          this.FakeDocumentBody()        }        .width('100%')        .padding({ bottom: 8 })      }      .width('100%')      .layoutWeight(1)      .edgeEffect(EdgeEffect.Spring)    }    .width('100%')    .height('100%')    .padding(18)    .backgroundColor('#FFFFFF')    .borderRadius(26)    .shadow({      radius: 12,      color: '#12000000',      offsetX: 0,      offsetY: 4    })  }​  @Builder  private RecognitionRow(item: RecognitionLine) {    Column({ space: 6 }) {      Row() {        Text(item.label)          .fontSize(12)          .fontColor('#9CA3AF')​        Blank()​        Text(item.confidence)          .fontSize(12)          .fontColor('#2F8F83')      }      .width('100%')​      Text(item.text)        .fontSize(14)        .fontColor('#111827')        .lineHeight(21)        .maxLines(2)        .textOverflow({ overflow: TextOverflow.Ellipsis })    }    .width('100%')    .padding(12)    .backgroundColor('#F7F8FA')    .borderRadius(16)  }​  @Builder  private SummaryRow(item: SummaryItem) {    Row() {      Text(item.label)        .fontSize(12)        .fontColor('#9CA3AF')        .width(72)        .flexShrink(0)​      Text(item.value)        .fontSize(13)        .fontColor('#374151')        .layoutWeight(1)        .maxLines(2)        .textOverflow({ overflow: TextOverflow.Ellipsis })    }    .width('100%')  }​  @Builder  private ResultPanel() {    Column({ space: 14 }) {      Row() {        Column({ space: 4 }) {          Text('识别结果')            .fontSize(20)            .fontWeight(FontWeight.Bold)            .fontColor('#111827')​          Text('和左侧原图对应校对')            .fontSize(13)            .fontColor('#6B7280')        }        .layoutWeight(1)      }      .width('100%')      .flexShrink(0)​      Scroll() {        Column({ space: 12 }) {          Column({ space: 10 }) {            ForEach(this.recognitionLines, (item: RecognitionLine) => {              this.RecognitionRow(item)            }, (item: RecognitionLine) => item.id.toString())          }          .width('100%')​          Column({ space: 10 }) {            Text('结构化摘要')              .fontSize(16)              .fontWeight(FontWeight.Medium)              .fontColor('#111827')​            ForEach(this.summaryItems, (item: SummaryItem) => {              this.SummaryRow(item)            }, (item: SummaryItem) => item.id.toString())          }          .width('100%')          .padding(14)          .backgroundColor('#F3F8F7')          .borderRadius(18)​          Text('识别到物业费缴纳金额、截止日期和办理地点,建议保存为待办提醒,并在截止日前一天通知。')            .fontSize(14)            .fontColor('#6B7280')            .lineHeight(22)            .maxLines(4)            .textOverflow({ overflow: TextOverflow.Ellipsis })            .padding(14)            .backgroundColor('#F7F8FA')            .borderRadius(18)        }        .width('100%')        .padding({ bottom: 8 })      }      .layoutWeight(1)      .width('100%')      .edgeEffect(EdgeEffect.Spring)​      Button('保存识别结果')        .height(44)        .width('100%')        .fontSize(15)        .fontColor('#FFFFFF')        .backgroundColor('#2F8F83')        .borderRadius(22)        .flexShrink(0)        .onClick(() => {          this.saveResult();        })​      Row({ space: 10 }) {        Button('重新识别')          .height(40)          .layoutWeight(1)          .fontSize(14)          .fontColor('#2F8F83')          .backgroundColor('#E6F4F1')          .borderRadius(20)​        Button('复制文本')          .height(40)          .layoutWeight(1)          .fontSize(14)          .fontColor('#4B5563')          .backgroundColor('#F3F4F6')          .borderRadius(20)      }      .width('100%')      .flexShrink(0)​      Text('已保存 ' + this.saveCount.toString() + ' 次')        .fontSize(12)        .fontColor('#6B7280')        .width('100%')        .textAlign(TextAlign.Center)        .flexShrink(0)    }    .width('100%')    .height('100%')    .padding(18)    .backgroundColor('#FFFFFF')    .borderRadius(26)    .shadow({      radius: 12,      color: '#10000000',      offsetX: 0,      offsetY: 4    })  }​  @Builder  private CompactSwitch() {    Row({ space: 8 }) {      this.PaneButton('原图', 'image')      this.PaneButton('识别结果', 'result')    }    .width('100%')    .padding(4)    .backgroundColor('#FFFFFF')    .borderRadius(22)    .flexShrink(0)  }​  @Builder  private MainContent() {    if (this.isExpanded()) {      Row({ space: this.twoColumnGap }) {        Column() {          this.PreviewPlaceholder()        }        .layoutWeight(1)        .height('100%')​        Column() {          this.ResultPanel()        }        .width(this.resultPanelWidth)        .height('100%')        .flexShrink(0)      }      .width('100%')      .height('100%')      .alignItems(VerticalAlign.Top)    } else {      Column({ space: 14 }) {        this.CompactSwitch()​        Column() {          if (this.activePane === 'image') {            this.PreviewPlaceholder()          } else {            this.ResultPanel()          }        }        .layoutWeight(1)        .width('100%')      }      .width('100%')      .height('100%')    }  }​  build() {    Column() {      Column({ space: 16 }) {        this.HeaderPanel()​        Column() {          this.MainContent()        }        .layoutWeight(1)        .width('100%')      }      .width(this.getContentWidth())      .height('100%')      .padding({        left: this.getPagePadding(),        right: this.getPagePadding(),        top: 18,        bottom: 16      })    }    .width('100%')    .height('100%')    .alignItems(HorizontalAlign.Center)    .backgroundColor('#F6F7F9')    .onAreaChange((_: Area, newValue: Area) => {      const width = Number(newValue.width);      if (!Number.isNaN(width) && width > 0) {        this.pageWidth = width;      }    })  }}


©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS

暂无评论数据

加载中...

发布

头像

小雨同学

产品总监、独立开发者社群主理人、资深全栈工程师,HarmonyOS应用开发者高级认证,PMP认证,CSDN博客专家,鸿蒙极客,Trae Fellow,阿里云社区专家博主、51CTO 博客专家、OpenTiny 优秀布道师、科大讯飞荣誉讲师。

16

帖子

0

提问

26

粉丝

关注
热门推荐
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 商务内容合作QQ:2291221 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255