3.细解鸿蒙之元服务UX上架标准-挖孔区适配

169 阅读8分钟

细解鸿蒙之元服务UX上架标准-挖孔区适配

是否必须遵守:必须

标准项描述:在各类应用程序的设计与开发过程中,界面布局需要充分考虑摄像头挖孔区域,以实现全面且有效的适配。这一适配过程涉及多个方面,以下详细阐述:

适配目标

确保应用界面在摄像头挖孔区域周围的显示和交互功能正常,优化用户体验。当用户使用应用时,挖孔区域不会干扰到界面内容的展示,且应用能够在挖孔区域提供良好的交互操作。

适配内容

1.显示布局

内容调整:应用需要对挖孔区域周围的内容进行重新布局。例如,在主屏幕界面上,当摄像头挖孔位于屏幕顶部时,附近的图标、文字等元素需要进行合理调整,避免被挖孔遮挡。这可能涉及到将原本在挖孔位置的信息移到其他位置,或者调整字体大小、图标尺寸等,以保证内容的完整性和可读性。

背景设计:背景图像或图案需要与挖孔区域相协调。例如,在壁纸设计中,壁纸图案可能需要避开挖孔区域,或者在挖孔周围设置特殊的过渡效果,使挖孔与整体背景融合得更加自然。这样可以避免挖孔区域在视觉上显得突兀,提升整体美观度。

显示比例:应用要根据挖孔区域的位置和尺寸,调整显示比例。例如,在一些应用中,挖孔区域可能会占用一定的屏幕空间,导致屏幕显示比例发生变化。应用需要根据这种变化,调整内容的显示方式,确保在挖孔区域周围的内容能够正常显示,不会出现拉伸或变形等情况。

  1. 交互功能

触摸操作:应用需要对挖孔区域周围的触摸操作进行优化。由于挖孔区域的存在,触摸操作可能会受到影响。例如,在挖孔附近进行触摸操作时,可能会出现误操作的情况。应用需要通过设置触摸区域的敏感度、手势识别等方式,确保用户能够准确地进行触摸操作。例如,当用户在挖孔附近进行滑动操作时,应用能够准确识别手势,并做出相应的响应。

功能按钮:在挖孔区域周围设置合适的功能按钮。例如,在拍照应用中,挖孔附近可能会设置一些拍照、录像等功能按钮。这些按钮需要根据挖孔区域的位置和用户操作习惯进行合理布局,方便用户操作。同时,按钮的大小、位置和形状也需要考虑到挖孔区域的影响,确保用户能够方便地点击按钮。

通知提示:应用在挖孔区域周围的通知提示也需要进行适配。例如,当有新消息或通知时,通知内容可能会在挖孔附近显示。应用需要确保通知内容不会被挖孔遮挡,并且能够清晰地显示。这可能涉及到调整通知的位置、字体大小等,以保证用户能够及时获取通知信息。

适配方法

  1. 技术手段

检测与识别:利用设备的传感器和系统接口,检测挖孔区域的位置和尺寸。通过代码编写,获取挖孔区域的相关信息,以便应用进行相应的适配处理。例如,在应用开发过程中,使用设备的摄像头传感器来检测挖孔区域的位置和大小。

布局调整:根据挖孔区域的位置和尺寸,通过代码调整应用的布局。例如,在应用的布局文件中,使用特定的布局参数来调整挖孔区域周围的元素位置和大小。同时,利用响应式设计技术,使应用能够根据不同屏幕尺寸和挖孔位置进行自动调整。

图形处理:对挖孔区域进行图形处理,优化显示效果。例如,通过图像处理技术对挖孔区域周围的图像进行裁剪、拉伸等操作,使挖孔区域与整体界面融合得更加自然。同时,应用还可以利用动画效果来增强挖孔区域的视觉效果。

2.测试与优化

模拟测试:在开发过程中,通过模拟不同设备的挖孔区域进行测试。利用模拟器或测试设备,模拟挖孔区域的位置和尺寸,测试应用在不同挖孔区域的显示和交互效果。例如,在模拟器上模拟挖孔区域的位置和大小,测试应用在该区域的显示和操作情况。

用户反馈:收集用户反馈,了解用户在挖孔区域的使用体验。通过用户反馈,发现应用在挖孔区域存在的问题,并及时进行优化。例如,用户可能会反馈挖孔区域周围的显示不清晰、操作不方便等问题,开发团队根据这些反馈进行针对性的改进。

优化调整:根据测试结果和用户反馈,对应用进行优化调整。例如,对挖孔区域周围的显示和交互功能进行调整,优化应用的性能和用户体验。同时,不断改进应用的适配策略,提高应用在挖孔区域的适配效果。

总之,界面布局适配摄像头挖孔区域是一个复杂而细致的过程,需要综合考虑多种因素,通过技术手段和测试优化,确保应用在挖孔区域能够实现良好的显示和交互功能,提升用户体验。 --javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

// 当窗口阶段创建时执行的函数
onWindowStageCreate(windowStage: window.WindowStage): void {
  // 将 windowStage 存储到 AppStorage 中,使用键 'context'
  AppStorage.setOrCreate('context', windowStage);
  // 获取主窗口
  windowStage.getMainWindow((err: BusinessError, data) => {
    // 存储错误代码
    let errCode: number = err.code;
    // 设置窗口为全屏显示状态
    data.setWindowLayoutFullScreen(true);
    // 要隐藏的系统栏名称数组,这里包含 'status' 和 'navigation'
    let names: Array<'status' | 'navigation'> = [];
    // 设置窗口系统栏的可见性,这里是隐藏顶部状态栏
    data.setWindowSystemBarEnable(names, (err: BusinessError) => {
      if (err.code) {
        // 若设置系统栏可见性时出错,打印错误信息
        console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err));
        return;
      }
      // 若设置系统栏可见性成功,打印成功信息
      console.info('Succeeded in setting the system bar to be visible.');
    });
  })
  //...
}







import { display, promptAction, window } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { batteryInfo } from '@kit.BasicServicesKit';

// 定义一个类来存储文本的左右边距信息
class TextMargin {
  left: number = 0; // 状态栏左偏移量
  right: number = 0; // 状态栏右偏移量
}

// 标记该组件为入口组件
@Entry
// 声明该类为组件
@Component
struct Index {
  // 存储当前日期
  @State date: Date = new Date();
  // 存储顶部状态栏显示的时间
  @State currentTime: string = ''; 
  // 存储不可用区域数据
  @State boundingRect: display.Rect[] = []; 
  // 存储屏幕宽度
  @State screenWidth: number = 0; 
  // 存储显示对象
  @State displayClass: display.Display | null = null; 
  // 存储顶部状态栏偏移量
  @State topTextMargin: TextMargin = { left: 0, right: 0 }; 
  // 从存储中获取 UIAbilityContext,使用键 'context'
  @StorageLink('context') context: common.UIAbilityContext | undefined =
    AppStorage.get('context'); 

  // 组件即将显示时执行的函数
  aboutToAppear(): void {
    // 获取默认的显示对象
    this.displayClass = display.getDefaultDisplaySync();
    // 获取屏幕切口信息
    display.getDefaultDisplaySync().getCutoutInfo((err, data) => {
      if (err.code!== 0) {
        // 若获取切口信息失败,打印错误信息
        console.log('getCutoutInfo failed. error is:', JSON.stringify(err));
        return;
      }
      // 存储切口信息的边界矩形数组
      this.boundingRect = data.boundingRects;
      // 计算并存储顶部状态栏的偏移量
      this.topTextMargin = this.getBoundingRectPosition();
    })
    // 获取当前日期的小时数
    let hours = this.date.getHours();
    // 获取当前日期的分钟数
    let minutes = this.date.getMinutes();
    // 将小时和分钟组合成时间字符串,分钟小于 10 时在前面加 0
    this.currentTime = hours.toString() + ':' + (minutes < 10? '0' + minutes : minutes.toString());
  }

  // 组件即将消失时执行的函数
  aboutToDisappear() {
    if (this.context!== undefined) {
      // 获取最后一个窗口
      window.getLastWindow(this.context, async (err, data) => {
        if (err.code!== 0) {
          // 若获取最后一个窗口失败,打印错误信息
          console.log('getLastWindow failed. error is:', JSON.stringify(err));
          // 将系统栏设置为可见
          data.setWindowSystemBarEnable(['status', 'navigation']);
          // 将窗口布局设置为非全屏
          data.setWindowLayoutFullScreen(false);
        }
      })
    }
  }

  // 计算边界矩形位置的函数
  getBoundingRectPosition(): TextMargin {
    if (this.boundingRect!== null && this.displayClass!== null && this.boundingRect[0]!== undefined) {
      // 计算不可用区域右侧到屏幕右边界的距离
      let boundingRectRight: number =
        this.displayClass.width - (this.boundingRect[0].left + this.boundingRect[0].width);
      // 获取不可用区域左侧到屏幕左边界的距离
      let boundingRectLeft: number = this.boundingRect[0].left;
      // 部分设备不可用区域在中间时存在左右距离会有 10 像素以内的差距,获取到的左右距离差值绝对值小于 10 都按照不可用区域位于中间处理
      if (Math.abs(boundingRectLeft - boundingRectRight) <= 10) {
        return { left: 0, right: 0 };
      }
      if (boundingRectLeft > boundingRectRight) {
        // 不可用区域在右边时的偏移量设置
        return { left: 0, right: this.displayClass.width - boundingRectLeft };
      } else if (boundingRectLeft < boundingRectRight) {
        // 不可用区域在左边时的偏移量设置
        return { left: this.boundingRect[0].left + this.boundingRect[0].width, right: 0 };
      }
    }
    return { left: 0, right: 0 };
  }

  build() {
    // 使用 Stack 组件进行布局
    Stack() {
      // 显示一张图片,使用资源 $r('app.media.digging_hole_screen_2048game')
      Image($r('app.media.digging_hole_screen_2048game'))
      .objectFit(ImageFit.Fill)
      .width('100%')
      .height('100%')
      .onClick(() => {
          // 点击图片时显示一个暂未开发的提示
          promptAction.showToast({
            message: '该功能暂未开发',
            duration: 2000
          })
        })
      // 使用 Column 组件进行布局
      Column() {
        // 使用 Flex 组件进行布局,方向为行,元素之间的空间分布为两端对齐
        Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) {
          // 显示时间文本
          Text(this.currentTime) 
          .fontSize(16)
          .fontColor(Color.Black)
          .fontWeight(FontWeight.Regular)
          .padding({ left: 12 })
          .margin({
              left: px2vp(this.topTextMargin.left),
              top: 14
            }) 
          // 显示电池电量文本
          Text(batteryInfo.batterySOC.toString() + '%')
          .fontSize(16)
          .fontColor(Color.Black)
          .fontWeight(FontWeight.Regular)
          .padding({ right: 16 })
          .margin({
              right: px2vp(this.topTextMargin.right),
              top: 14
            }) 
        }
      .width('100%')
      }
    .width('100%')
    }
  .width('100%')
  .height('100%')
  .alignContent(Alignment.TopStart)
  }
}

PS:实际项目中如有出入,请告知博主,博主会第一时间修改得哇~