HarmonyOS 尺寸适配算法

背景

今日看到HarmonyOS论坛,有研发求助关于官方提供的一段缩放算法的问题.这个求助问题其实深究的话还是比较有意思的,比如,如何在HarmonyOS 系统上出设计稿?

先解决今天的求助问题,问题描述如下

求助问题

developer.huawei.com/consumer/cn...

问题描述: adaptDimension这个方法里面,为什么不使用display的height,而是自己通过scale算出一个虚拟高度呢?还有后面的designDim跟virtualDim为什么要这么计算?

问题1: 为什么要计算虚拟高度,即 virtualHeight

ini 复制代码
static adaptDimension(value: number): number {
  let deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display;
  let widthScale = deviceDisplay.width / DESIGN_WIDTH;
  let virtualHeight = widthScale * DESIGN_HEIGHT;
  let designDim = Math.sqrt(DESIGN_WIDTH * DESIGN_WIDTH + DESIGN_HEIGHT * DESIGN_HEIGHT);
  let virtualDim = Math.sqrt(deviceDisplay.width * deviceDisplay.width + virtualHeight * virtualHeight);
  return virtualDim * value / designDim;
}

问题2: 输出值为什么采用 virtualDim * value / designDim 这个公式

答案核心

这是一个以宽为基准的等比例缩放算法

因此,才会出现adaptDimension中的所有代码逻辑

解析

假设设计稿的屏幕是60 x 120, 设计稿中的蓝色图标是 30 x 60, 那么我们想象一下,如果要等比例放大到真实屏幕(240 x 340),那么设计稿的60x120,应该变为多少?

有两种基准:1. 以屏幕宽度为基准 2. 以屏幕高度为基准

我们可以尝试推演一下两种基准

以屏幕宽度为基准

真实屏幕的分辨率为 240 x 340

那么设计稿以同等宽高比放大之后的高度应该为: (120 * 240) / 60 = 480

注意,这个高度比屏幕实际高度大

那么图标以宽占比放大之后的宽度应该为: (30 * 240) / 60 = 120

以屏幕高度为基准

真实屏幕的分辨率为 240 x 340

那么设计稿以同等宽高比放大之后的宽度应该为: (60 * 340) / 120 = 170

注意,这个高度比实际屏幕宽度小

那么图标以高占比放大之后的高度应该为: (60 * 340) / 120 = 170

两种基准的效果图

图中第一行示意图是采用"以屏幕宽为基准"的算法,第二行示意图是采用"以屏幕高度为基准"

基准算法实现

回看"问题1"中的算法实现,其采用的是"以屏幕宽为基准"的算法

ini 复制代码
const DESIGN_WIDTH = 360;
const DESIGN_HEIGHT = 780;
...

static adaptDimension(value: number): number {
   //获取分辨率,具体的获取代码是在下段代码中
  let deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display;
  
  //计算设计稿与设备的宽度缩放比例
  let widthScale = deviceDisplay.width / DESIGN_WIDTH;
  
  //通过宽度的缩放比例计算出,deviceDisplay.width宽度应该对应的高度
  let virtualHeight = widthScale * DESIGN_HEIGHT;
  
  //计算设计稿对角线长度
  let designDim = Math.sqrt(DESIGN_WIDTH * DESIGN_WIDTH + DESIGN_HEIGHT * DESIGN_HEIGHT);
  
  //计算设计稿对应的理想屏幕对角线长度
  let virtualDim = Math.sqrt(deviceDisplay.width * deviceDisplay.width + virtualHeight * virtualHeight);
  
  // 由于是采用宽高比,以宽为基准的计算方法,所以对于输入值来讲,输出值的计算公式为
  // virtualDim / 理想值 = designDim / value
  // 即:virtualDim*value / designDim
  
  return virtualDim * value / designDim;
}

...
这个文件是Ability 复制代码
async onWindowStageCreate(windowStage: window.WindowStage) {
  //获取分辨率, 将获取到的分辨率存放在GlobalContext这个文件中的Map变量中
  GlobalContext.getContext().setObject('display', await display.getDefaultDisplaySync());
 ......
}

接下来,再用"以屏幕高度为基准"来实现一遍

ini 复制代码
adaptDimension2(value: number): number {
  let deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display;

  let deviceHeight = deviceDisplay.height
  console.log('display:' + deviceDisplay.width + 'x' + deviceDisplay.height)

  let heightScale = deviceHeight / DESIGN_HEIGHT;
  let virtualWidth = heightScale * DESIGN_WIDTH;
  let designDim = Math.sqrt(DESIGN_WIDTH * DESIGN_WIDTH + DESIGN_HEIGHT * DESIGN_HEIGHT);
  let virtualDim = Math.sqrt(deviceHeight * deviceHeight + virtualWidth * virtualWidth);
  return virtualDim * value / designDim;
}

质疑

"以屏幕宽度为基准" 这个通过对角线方式实现的等比例缩放算法是不是有点复杂了?

图标.宽 / 设计稿.宽 = 目标图标.宽 / 真实屏幕.宽

目标图标.宽 = 图标.宽 * 真实屏幕.宽 / 设计稿.宽

假设:设计稿宽 360,高780, 图标.宽 30

那么,目标图标.宽 = 30 * 真实屏幕.宽 / 360

真实屏幕.宽 可以通过 display.getDefaultDisplaySync() API获取到

codelabs样例库

关于HarmonyOS实践教程,有一个Demo库, 在这个库中,可以找到和这个研发人员求助的所有函数使用样例代码。

  1. codelabs/AlarmClock【API 9】
  2. codelabs/AnimateRefresh【API 9】
  3. codelabs/TransitionAnimation【API 9】
  4. codelabs/HarmonyOS_NEXT/TransitionAnimation/【API 10】
  5. codelabs/HarmonyOS_NEXT/AnimateRefresh/【API 10】

结尾

关于适配,终极目标是要得到UED的还原认可,所以,应该采用哪种算法,最好了解清楚UED还原的过程。要不然容易陷入无休止的返工,甚至永远无法达到适配要求。

相关推荐
Random_index1 小时前
#Uniapp篇:支持纯血鸿蒙&发布&适配&UIUI
uni-app·harmonyos
鸿蒙自习室5 小时前
鸿蒙多线程开发——线程间数据通信对象02
ui·harmonyos·鸿蒙
SuperHeroWu77 小时前
【HarmonyOS】鸿蒙应用接入微博分享
华为·harmonyos·鸿蒙·微博·微博分享·微博sdk集成·sdk集成
zhangjr05759 小时前
【HarmonyOS Next】鸿蒙实用装饰器一览(一)
前端·harmonyos·arkts
诗歌难吟46416 小时前
初识ArkUI
harmonyos
SameX16 小时前
HarmonyOS Next 设备安全特性深度剖析学习
harmonyos
郭梧悠17 小时前
HarmonyOS(57) UI性能优化
ui·性能优化·harmonyos
郝晨妤1 天前
鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
android·ios·华为od·华为·华为云·harmonyos·鸿蒙
Peace*1 天前
HarmonyOs鸿蒙开发实战(16)=>沉浸式效果第一种方案一窗口全屏布局方案
harmonyos·鸿蒙·鸿蒙系统
howard20051 天前
鸿蒙实战:页面跳转传参
harmonyos·跳转·router·传参