作者:韓茹
公司:程序咖(北京)科技有限公司
鴻蒙巴士專欄作家
當年的Android中,有的sp、dp。還有dpi等概念。
- dpi,dots per inch,代表屏幕像素密度。
- dp,device independent pixels(設備獨立像素,等同於dip),不依賴於像素
- sp,scale-independent pixels(縮放獨立像素,等同於sip),和dp類似,允許由用戶自定義文字尺寸大小(如小、正常、大、超大等)
所以在Android應用程序的mipmap或drawable目錄下,根據dpi的不同分為ldpi、mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi等。
HarmonyOS在借鑒Android經驗的同時,也提出了創新。
對於很大一部分程序員用戶來說,會比較糾結這些問題:圖片的大小尺寸定義為多大尺寸比較合理?應該放在什么標准的dpi中才能得到更好的適配效果?在HarmonyOS中,程序員可不必將時間和精力過多花費在此。在放置圖片的media目錄下也沒有按照dpi來進行區分。
為了解決由於屏幕規格不同而引起的頁面適配問題,HarmonyOS 提供了針對不同屏幕尺寸進行界面自適應適配的7種原子布局能力,使設計師可以使用原子布局能力來定義元素在不同尺寸的界面上的自適應規則。詳見官方文檔:https://developer.harmonyos.com/cn/docs/design/des-guides/layout-0000001111593946
HarmonyOS 重新定義了界面換算單位,使用虛擬像素作為一台設備針對應用而言所具有的虛擬尺寸,是定義應用內參數尺寸的度量單位。虛擬像素也是一種可靈活使用和縮放的單位,它與屏幕像素的關系是 1vp 約等於 160dpi 屏幕密度設備上的 1px。在不同密度的設備之間,HarmonyOS 會針對性的轉換設備間對應的實際像素值。
一、px
px:像素的單位,1px代表手機屏幕上的一個像素點。比如常見的手機分辨率有320×480,480×800,1080×1920等,這些數值的單位都是px;由於px在不同手機上的大小不同,差別較大,適配性太差,不建議使用。
由於手機分辨率不同,應用中用到的圖片某個固定尺寸大小的圖片,或某個固定字號的文本就會因手機分辨力不同而出現失真或變形的情況,為了更好的適配不同的手機,故而就有了不依賴與像素的單位sp與dp。
二、vp
vp:虛擬像素(virtual pixel)是一台設備針對應用而言所具有的虛擬尺寸(區別於屏幕硬件本身的像素單位)。它提供了一種靈活的方式來適應不同屏幕密度的顯示效果。
使用虛擬像素vp,使元素在不同密度的設備上具有一致的視覺體量。
三、fp
fp,font-size pixels,字體像素單位,其大小規范默認情況下與vp相同,但如果開發者在設置中修改了字體顯示大小,就會在vp的基礎上乘以scale系數。即默認情況下 1 fp = 1vp,如果設置了字體顯示大小,則會根據實際情況自動設置 1fp = 1vp * scale。
四、AttrHelper工具類
為了方便開發者對尺寸長度的管理,官方提供了AttrHelper工具類,可實現fp、vp、px之間的相互轉換,簡直不要太方便。以下是部分方法:
Modifier and Type | Method | Description |
---|---|---|
static int | fp2px(float value, float density) | Converts a font-size pixel (fp) to a pixel value based on the screen density. |
static int | fp2px(float value, float density, float fontRatio) | Converts a font-size pixel (fp) value to a pixel value based on the screen density and font ratio. |
static int | fp2px(float value, Context context) | Converts a font-size pixel (fp) to a pixel value based on the screen context. |
static float | getDensity(Context context) | Obtains the display density. |
static int | vp2px(float value, float density) | Converts a virtual pixel (vp) to a pixel value based on the screen density. |
static int | vp2px(float value, Context context) | Converts a virtual pixel (vp) to a pixel value based on the screen context. |
另外,除fp、vp、px的相互轉換API以外,該工具類還提供了關於density、字體名稱與其值等的轉換方法,非常非常的貼心。詳見官方文檔:https://developer.harmonyos.com/cn/docs/documentation/doc-references/attrhelper-0000001054518726
在HarmonyOS中,我們想布局一個頁面,可以使用xml文件,也可以通過代碼的形式。這里我們使用之前講PositionLayout布局的一個例子。
重新創建一個布局文件:position_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<PositionLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:background_element="#99FDF5E6"
>
<Text
ohos:id="$+id:text1"
ohos:height="50vp"
ohos:width="200vp"
ohos:background_element="#99FFE4B5"
ohos:layout_alignment="horizontal_center"
ohos:text="Title"
ohos:text_size="20fp"
ohos:text_alignment="center"
/>
<Text
ohos:id="$+id:text2"
ohos:height="200vp"
ohos:width="200vp"
ohos:background_element="#99FFE4B5"
ohos:text="Content"
ohos:text_alignment="center"
ohos:text_size="20fp"/>
<Text
ohos:id="$+id:text3"
ohos:height="200vp"
ohos:width="200vp"
ohos:background_element="#99FFE4B5"
ohos:text="Content"
ohos:text_alignment="center"
ohos:text_size="20fp"/>
</PositionLayout>
然后打開slice下的MainAbilitySlice文件,首先修改一下要加載的布局文件:
super.setUIContent(ResourceTable.Layout_position_layout);
然后獲取Text組件,並設置positon,其實就是通過id獲取Text組件,想要設置X軸和Y軸的偏移量,調用setPosition()方法,來進行設置即可。
public void setPosition(int coordX, int coordY);
//Sets the position of the upper-left corner of a component, relative to the parent layout.
但是該方法的參數為int類型,單位為px。如果想使用vp或者fp等單位。需要借助於一個類AttrHelper。
其實在代碼中,很多方法的參數設置都是以px為單位。
Java示例代碼如下:
package com.example.positionlayout.slice;
import com.example.positionlayout.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.Text;
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_position_layout);
//獲取Text組件
Text title = (Text)findComponentById(ResourceTable.Id_text1);
Text content1 = (Text)findComponentById(ResourceTable.Id_text2);
Text content2 = (Text)findComponentById(ResourceTable.Id_text3);
// ohos:position_x="200"
// ohos:position_y="60"
//這里的參數200,60,單位都是像素px。
title.setPosition(200, 60);
/*
因為在xml布局文件中,我們使用的是vp,不是px,但是setPosition()方法的單位是px,所以這里我們轉換一下。需要使用AttrHelper類。
ohos.agp.components.AttrHelper類:
提供了vp,fp到px的轉換
vp2px(float value, float density)-->static int基於屏幕密度將虛擬像素(vp)轉換為像素值。
*/
//AttrHelper.vp2px(20, AttrHelper.getDensity(this));//將20vp轉為px
// ohos:position_x="20vp"
// ohos:position_y="100vp"
content1.
(AttrHelper.vp2px(20, AttrHelper.getDensity(this)), AttrHelper.vp2px(100, AttrHelper.getDensity(this)));
// ohos:position_x="150vp"
// ohos:position_y="250vp"
content2.setPosition(AttrHelper.vp2px(150, AttrHelper.getDensity(this)), AttrHelper.vp2px(250, AttrHelper.getDensity(this)));
}
}
然后啟動模擬器運行:

這里需要格外強調一下,在設置控件的寬度和高度上,我們習慣了在xml布局中使用vp而不使用px(像素)。在設置字體大小的時候,我們使用fp也不使用px。
特別鳴謝:
https://www.harmonybus.net/archives/2048
更多內容:
1、社區:鴻蒙巴士https://www.harmonybus.net/
2、公眾號:HarmonyBus
3、技術交流QQ群:714518656