HarmonyOS NEXT鸿蒙开发 ArkUI:尺寸单位 px、vp、%百分比、fp

px (逻辑像素 - Logical Pixel)

  • px 在 ArkUI 中代表逻辑像素(Logical Pixel),也称为设备独立像素(Device-Independent Pixel, DIP)。
  • 它是一种与屏幕物理像素密度无关的单位。系统会根据设备的实际屏幕密度(DPI)自动将 px 转换为合适的物理像素数量。
  • 目的:确保 UI 元素在不同分辨率和屏幕密度的设备上,呈现的物理尺寸(如毫米、英寸)大致相同,提供一致的视觉体验。

特点与用法

  • 布局通用性:px 可以用于定义组件的宽度、高度、边距、内边距、圆角、边框宽度等几乎所有尺寸属性。
  • 默认单位:在 ArkUI 中,许多尺寸属性如果不指定单位,通常默认就是 px。
Button('确定')
      .width('120px')     // 等同于 .width(120) 或 .width('120px')
      .height('40px')     // 等同于 .height('40px')
      .margin('16px')     // 四周边距 16px

与 vp 的关系

在 HarmonyOS 的文档和实践中,px 和 vp (虚拟像素) 经常被提及,它们在 ArkUI 中的行为非常相似,甚至在某些上下文中可以互换。vp 更强调“虚拟”和“与密度无关”的概念,而 px 在开发者习惯上更常见。在大多数布局场景下,使用 px 或 vp 效果一致,推荐使用 vp 以更明确地表达意图。

示例

@Entry
@Component
struct Example {
  build() {
    Column() {
      Text('标题')
        .fontSize(24)        // 字体大小 24px (不推荐用于字体)
        .fontWeight(FontWeight.Bold)

      Divider()              // 分割线
        .margin({ top: 16, bottom: 16 }) // 上下边距 16px
        .width('90%')        // 宽度为父容器的 90%
        .height(1)           // 高度 1px (细线)
    }
    .padding(20)             // 内边距 20px
  }
}

vp 虚拟像素(Virtual Pixel)

在 ArkUI 中,vp 是一个非常重要的尺寸单位,它的全称是 虚拟像素(Virtual Pixel)。

理解 vp 的关键在于它是一种与屏幕密度无关的逻辑单位,旨在帮助开发者构建在不同设备上具有一致视觉大小的用户界面。

为什么需要 vp?

现代移动设备的屏幕物理尺寸和分辨率(像素密度)千差万别。例如:

  • 一台手机可能有 480x800 的物理像素。
  • 另一台手机可能有 1080x1920 的物理像素。

如果直接使用物理像素 px 来定义 UI 元素的大小,在高分辨率的屏幕上,同样的 px 值会显得非常小,导致用户看不清内容;而在低分辨率的屏幕上,又可能显得过大。

vp 是如何工作的?

vp 通过一个 缩放因子 将逻辑尺寸映射到物理像素上。

  • 基准:通常,系统会设定一个基准密度(例如,以 160 dpi 为基准)。
  • 换算:在不同的屏幕上,系统会根据其实际的屏幕密度(dpi)自动计算出 vp 到物理像素 px 的转换比例。
    • 在基准密度(如 160 dpi)的设备上:1 vp ≈ 1 px
    • 在更高密度的设备上(如 320 dpi):1 vp ≈ 2 px(或其他比例)

这意味着,无论设备的实际物理像素密度是多少,一个 50vp 高的按钮,在不同设备上呈现给用户的物理尺寸(毫米/英寸)大致是相同的,从而保证了用户体验的一致性。

与其他单位的区别

单位 名称 特点
vp 虚拟像素 (Virtual Pixel) 与屏幕密度无关。用于布局尺寸(宽、高、边距、字体等),确保在不同设备上视觉大小一致。推荐用于大多数布局场景。
px 逻辑像素 (Logical Pixel) 在 ArkUI 中,px 实际上也经过了处理,通常是与 vp 等价或非常接近。但在某些上下文中,px 可能更偏向于“CSS 像素”的概念。一般情况下,vp 和 px 在效果上相似,但 vp 更明确地表达了“与密度无关”的意图。
% 百分比 相对于父容器尺寸的百分比。

使用建议

在定义组件的宽度、高度、外边距 (margin)、内边距 (padding)、圆角 (borderRadius) 等时,优先使用 vp。

Button('点击我')
    .width(200)        // 默认单位是vp,等同于 200vp
    .height(50vp)      // 明确指定vp
    .margin({ top: 20vp, bottom: 20vp })
    .borderRadius(8vp)

%百分比

在 ArkUI 中,%(百分比)是一个非常实用的尺寸单位,用于表示一个尺寸是其父容器对应尺寸的百分比。

它是一种相对单位,% 的值会随着父容器尺寸的变化而动态调整,这使得它在创建响应式和自适应布局时非常强大。


基本语法

% 单位通常以字符串形式使用:

// 语法
.componentMethod(value + '%')
// 或
.componentMethod(`${value}%`)

// 例子
.width('50%')   // 宽度为父容器宽度的 50%
.height('80%')  // 高度为父容器高度的 80%

核心作用:实现响应式布局

% 的最大优势在于其动态性。当父容器的尺寸因设备屏幕、窗口大小调整或内容变化而改变时,使用 % 定义的子组件尺寸会自动按比例缩放。

例子:创建一个居中卡片

@Entry
@Component
struct ResponsiveCard {
  build() {
    Column() { // 这个 Column 占据整个页面
      .width('100%')  // 明确占满父容器(页面)宽度
      .height('100%') // 明确占满父容器(页面)高度
      .justifyContent(FlexAlign.Center) // 垂直居中
      .alignItems(HorizontalAlign.Center) // 水平居中

      Column() { // 内部卡片
        .width('80%')  // 卡片宽度为父容器(页面)宽度的 80%
        .height('60%') // 卡片高度为父容器(页面)高度的 60%
        .backgroundColor(Color.White)
        .borderRadius(12)
        .shadow({ radius: 10, color: Color.Gray, offsetX: 0, offsetY: 4 })

        Text('欢迎使用')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 20 })

        Text('这是一个响应式卡片布局')
          .fontSize(16)
          .margin(10)
      }
    }
    .backgroundColor(Color.Gray) // 背景
  }
}

在这个例子中:

  • 无论设备是手机、平板还是折叠屏,内部的 Column(卡片)都会始终占据页面宽度的 80% 和高度的 60%。
  • 在小屏幕上,卡片会变小;在大屏幕上,卡片会变大,始终保持相对比例。

margin 和 padding 中的 %

% 也可以用于外边距和内边距,其百分比是相对于父容器的 宽度来计算的(即使用于 margin-top 或 padding-bottom 也是如此,这是 Web 标准中的常见行为,ArkUI 也遵循此逻辑)。

Column() {
  Text('内容')
    .margin('5%')     // 四周边距为父容器宽度的 5%
    .padding('10%')   // 四周内边距为父容器宽度的 10%
}
.width('80%')
.height(200)

使用注意事项

  1. 父容器必须有明确尺寸:

    • 百分比是相对于父容器的,如果父容器的宽度或高度是 0 或未定义(例如,一个 Column 默认高度由内容决定),那么 50% 的计算结果可能不符合预期。
    • 在需要精确控制的场景,确保父容器有明确的 width 和 height。
  2. 避免无限嵌套:

    • 虽然 % 很强大,但过度使用或在深层嵌套中使用可能导致布局计算复杂或出现意料之外的结果。
  3. 与 fr 的选择:

    • 在 Grid 或 Flex 布局中,如果你想让子组件平分剩余空间,使用 1fr 通常比 50% 更直观和可靠,因为它直接基于可用空间,而不是父容器的总尺寸。

总结

% 是 ArkUI 中实现响应式设计的关键工具之一。它允许你定义相对于父容器的尺寸,使得 UI 能够优雅地适应不同尺寸的屏幕和窗口。

核心要点:

  • 50% 表示父容器对应尺寸(宽或高)的 50%。
  • 用于 margin/padding 时,% 通常相对于父容器宽度计算。
  • 与 vp/px 的固定性相比,% 提供了动态和灵活的布局能力。
  • 在构建需要随屏幕大小变化的容器、卡片、全屏背景等时,% 是首选单位。

fp (字体像素 - Font Pixel)

  • fp 专用于字体大小(fontSize)。
  • 它不仅考虑了屏幕密度,还会根据用户的系统字体大小偏好进行额外缩放。

目的

确保文字的可读性,尊重用户的个性化设置(如视力障碍用户可能将系统字体设置得非常大)。

特点与用法

  • 专用于字体:fp 只能用于 fontSize 属性。

  • 响应用户偏好:这是 fp 与 px/vp 最关键的区别。如果用户在手机设置中将“字体大小”调为“超大”,那么使用 fp 的文本会相应地 变得更大,而使用 px/vp 的文本则 保持不变。

  • 可访问性要求:为了应用的可访问性(Accessibility),强烈推荐在所有文本的 fontSize 中使用 fp 而不是 px 或 vp。

示例

@Entry
@Component
struct AccessibleText {
  build() {
    Column() {
      Text('这是一个标题')
        .fontSize('24px')  // ❌ 不推荐。用户调整系统字体时,此文本大小不变。

      Text('这是一个重要的标题')
        .fontSize(24)  // ✅ 推荐!用户调整系统字体时,此文本会相应缩放。
        .fontWeight(FontWeight.Bold)

      Text('这是一段说明文字')
        .fontSize(16)  // ✅ 推荐!确保所有用户都能舒适阅读。
    }
    .padding(20)
  }
}

最佳实践建议

  1. 字体大小一律用 fp:

    • 这是最重要的规则。无论设计稿上标注的是多少 px,在代码中都应转换为 fp 用于 fontSize。
    • 例如,设计稿标注 16px 字体,在代码中写 .fontSize(16)。
  2. 布局尺寸优先用 vp:

    • 虽然 px 在 ArkUI 中可用,但为了更清晰地表达“与密度无关”的意图,推荐使用 vp 进行布局。
    • 例如:.width(100vp), .margin(10vp)。
  3. 理解单位背后的设计理念:

    • px/vp 保证了 UI 的视觉一致性。
    • fp 保证了 UI 的可访问性和用户友好性。

通过正确使用 px (或更推荐的 vp) 和 fp,你可以构建出既美观又包容的 HarmonyOS 应用。


原文出处:/show_1GW25dLclU3J.html