HarmonyOS 屏幕适配设计

1. armonyOS 屏幕适配设计

1.1. 像素单位

Harmony官方文档
  鸿蒙OS UI布局适配终极攻略 像素适配大法,此方法也适合Android
  ArkUI为开发者提供4种像素单位,框架采用vp为基准数据单位。
  vp相当于Android里的dp
  fp相当于Android里的sp
  官方是如何定义的呢,如下图
在这里插入图片描述

(1)px (Pixels)
  px代表屏幕上的像素点,是手机屏幕分辨率的单位,即屏幕物理像素单位。
(2)vp (Viewport Percentage)
  虚拟像素(virtual pixel)是一台设备针对应用而言所具有的虚拟尺寸(区别于屏幕硬件本身的像素单位)。它提供了一种灵活的方式来适应不同屏幕密度的显示效果。
  vp是视口百分比单位,基于视口(即浏览器窗口)的宽度或高度,屏幕密度相关像素,根据屏幕像素密度转换为屏幕物理像素,当数值不带单位时,默认单位vp。在实际宽度为1440物理像素的屏幕上,1vp约等于3px。它允许组件的大小根据视口的大小动态调整。常用于响应式设计,确保组件在不同屏幕尺寸上保持相对大小。
(3)lpx (Logical Pixels)
  lpx是逻辑像素单位,用于解决不同设备分辨率和像素密度的问题。
  lpx单位为实际屏幕宽度与逻辑宽度(通过designWidth配置)的比值,designWidth默认值为720。当designWidth为720时,在实际宽度为1440物理像素的屏幕上,1lpx为2px大小。
(4)fp (font pixel)
  l字体像素(font pixel) 大小默认情况下与 vp 相同,即默认情况下 1 fp = 1vp。如果用户在设置中选择了更大的字体,字体的实际显示大小就会在 vp 的基础上乘以用户设置的缩放系数,即 1 fp = 1 vp * 缩放系数。
  lpx是逻辑像素单位,用于解决不同设备分辨率和像素密度的问题。
  lpx单位为实际屏幕宽度与逻辑宽度(通过designWidth配置)的比值,designWidth默认值为720。当designWidth为720时,在实际宽度为1440物理像素的屏幕上,1lpx为2px大小。
在这里插入图片描述

1.2. 逻辑宽度

  "window": {
    "designWidth": 720,
    "autoDesignWidth": false
  }
属性名称含义数据类型是否可缺省
designWidth标识页面设计基准宽度。以此为基准,根据实际设备宽度来缩放元素大小。数值可缺省,缺省值为720px。
autoDesignWidth标识页面设计基准宽度是否自动计算。当配置为true时,designWidth将会被忽略,设计基准宽度由设备宽度与屏幕密度计算得出。布尔值可缺省,缺省值为false。

在这里插入图片描述

  它基于设备的像素密度进行转换,以提供一致的视觉尺寸。当你缩放宽高的时候,可以自动适配。

1.3. 核心

  vp这个概念实际上来源于android的dp,是一个屏幕密度值,用来解决不同比例和屏幕像素的差异。
  vp虽然也做到了自适应,但是计算方式是根据屏幕斜边来计算。这也导致在UI还原遇到的最大问题就是很难按照设计图进行快速的编写代码。并且相同的vp,在不同机型上展示的效果是有问题的。即虽然进行了自适用,但是因为计算方式是按照斜边,所以在水平方向上的宽度在各机型展示的实际宽度百分比是不一致,导致UI还原上存在问题。
  lpx是以720px为基准计算的相对像素;目前主流的屏幕720分辨率已经很低配了。我个人建议直接用LPX,但是目前大部分的APi都是基于VP来计算的。这样在实际的开发中,可以用函数转换。
  Harmony要多一个lpx,是因为鸿蒙是跨端的,也就是存在 pc、pad 等,在其他的端存在视窗可以拉长缩小的情况,所以这个主要是应用在需要适配多端的场景。

1.4. 适配机型

  每台设备的屏幕都有宽高,比如720*1080 就是说这台手机宽有720px,高有1080个px
  鸿蒙OS获取宽高的API为:

import { display } from '@kit.ArkUI'

export class DisPlayInfo {
  private screenWidth = 0;
  private screenHeight = 0;

  constructor() {
    let screenWidth = display.getDefaultDisplaySync().width;
    let screenHeight = display.getDefaultDisplaySync().height;
  }
}

  而我们在写界面时,UI会给我们切一份以宽xxx 高xxx 为基准提供一套设计图给到我们,假设高为:1334 , 宽为:750

import { display } from '@kit.ArkUI'

export class DisPlayInfo {
    private screenWidth = 0;
    private screenHeight = 0;
    private static readonly STANDARD_WIDTH = 750;
    private static readonly STANDARD_HEIGHT = 1334;

    constructor() {
        let screenWidth = display.getDefaultDisplaySync().width;
        let screenHeight = display.getDefaultDisplaySync().height;
    }
}

  这个时候我们就可以得到一个比例,UI设计标准和屏幕的一个宽高比

let widthRadio = screenWidth /STANDARD_WIDTH 
let heightRadio = screenHeight /STANDARD_HEIGHT 

  这时,假设有一个Btn UI设计图上的宽为220, 高为64,我们就可以计算出这个btn在屏幕上的实际px

let realWidth = widthRadio *btnWidth
let realHeight = heightRadio *btnHeight

  得到了实际宽高,我直接填到布局里就OK,完整代码如下,

import { display } from '@kit.ArkUI'

export class DisPlayInfo {
    private screenWidth = 0;
    private screenHeight = 0;
    private static readonly STANDARD_WIDTH = 750;
    private static readonly STANDARD_HEIGHT = 1334;

    constructor() {
        let screenWidth = display.getDefaultDisplaySync().width;
        let screenHeight = display.getDefaultDisplaySync().height;
        this.screenWidth = Math.min(screenWidth, screenHeight);
        this.screenHeight = Math.max(screenWidth, screenHeight);
        console.info("screenWidth " + screenWidth + " screenHeight " + this.screenHeight)
    }

    public getWidth(width: number): PX {
        let realWidth: number = Math.floor(width * this.screenWidth / DisPlayInfo.STANDARD_WIDTH)
        return `${realWidth}px`
    }

    public getHeight(height: number): PX {
        return `${Math.floor((this.screenHeight / DisPlayInfo.STANDARD_HEIGHT) * height)}px`
    }
}

  使用,

import { router } from '@kit.ArkUI';
import { TitleBar } from '../../../components/common/TitleBar';
import { RouterParams } from '../../../helper/RouterHelper';
import { DisPlayInfo } from '../../../utils/DisPlayInfo';

@Entry
@Component
struct ScreenAdapter2Page {
  @State pageTitle: string = "屏幕适配"
  @State message: string = 'Hello World';
  displayInfo = new DisPlayInfo()

  aboutToAppear() {
    try {
      this.pageTitle = (router
        .getParams() as RouterParams).title
    } catch (e) {
    }
  }

  build() {
    Column() {
      TitleBar({ pageTitle: $pageTitle })
      Image($r('app.media.app_icon'))
        .width(this.displayInfo.getWidth(80))
        .height(this.displayInfo.getWidth(80))
        .backgroundColor($r('app.color.primary_gray_dark'))
    }
  }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值