本案例介绍像素单位的基本知识与像素单位转换API的使用。通过像素转换案例,向开发者讲解了如何使用像素单位设置组件的尺寸、字体的大小以及不同像素单位之间的转换方法。主要功能包括:
- 展示了不同像素单位的使用。
- 展示了像素单位转换相关API的使用。
一、案例页面展示
二、案例目录文件结构
三、项目资源初始化
color.json
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
},
{
"name": "page_background",
"value": "#F1F3F5"
},
{
"name": "item_background",
"value": "#FFFFFF"
},
{
"name": "blue_background",
"value": "#007DFF"
},
{
"name": "title_font",
"value": "#182431"
},
{
"name": "font_background",
"value": "#FAFAFA"
},
{
"name": "notice_font",
"value": "#FF7500"
}
]
}
float.json
{
"float": [
{
"name": "btn_height",
"value": "40vp"
},
{
"name": "value_height",
"value": "28vp"
},
{
"name": "item_padding",
"value": "12vp"
},
{
"name": "subtitle_margin_top",
"value": "2vp"
},
{
"name": "blue_margin_top",
"value": "4vp"
},
{
"name": "title_margin_top",
"value": "6vp"
},
{
"name": "desc_margin_top",
"value": "8vp"
},
{
"name": "item_margin_top",
"value": "18vp"
},
{
"name": "desc_line_height",
"value": "20fp"
},
{
"name": "subtitle_line_height",
"value": "16fp"
},
{
"name": "name_font_size",
"value": "16fp"
},
{
"name": "title_font_size",
"value": "14fp"
},
{
"name": "subtitle_font_size",
"value": "12fp"
},
{
"name": "large_font_size",
"value": "24fp"
},
{
"name": "item_border_radius",
"value": "24vp"
},
{
"name": "notice_border_radius",
"value": "12vp"
},
{
"name": "value_border_radius",
"value": "4vp"
},
{
"name": "label_opacity",
"value": "0.6"
}
]
}
string.json(英文)
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
},
{
"name": "pixel_introduce",
"value": "Pixel Introduce"
},
{
"name": "pixel_conversion",
"value": "Pixel Conversion"
},
{
"name": "HarmonyHeiTi",
"value": "HarmonyHeiTi"
},
{
"name": "HarmonyHeiTi_Medium",
"value": "HarmonyHeiTi-Medium"
},
{
"name": "font_desc",
"value": "This is a text for %dfp"
},
{
"name": "notice",
"value": "For the conversion between lpx and px, set designWidth based on the site requirements."
},
{
"name": "px_unit",
"value": "Physical pixel unit of the screen."
},
{
"name": "vp_unit",
"value": "Screen density-related pixels, which are converted to screen physical pixels based on the screen pixel density."
},
{
"name": "lpx_unit",
"value": "Logical pixel unit of the window. The unit of lpx is the ratio of the actual screen width to the logical width (configured by designWidth)."
},
{
"name": "fp_unit",
"value": "Font pixel, similar to vp, varies with the system font size setting."
},
{
"name": "vp_desc",
"value": "On a device with a pixel density of 160 dpi, 1vp = 1px, corresponding physical screen pixels = (Screen pixel density/160) px."
},
{
"name": "fp_desc",
"value": "By default, the value is the same as that of vp, that is, 1vp=1fp. If the system font is manually adjusted, scale indicates the scaling ratio. The font size after setting (unit: fp) equals the font size before setting x scale."
}
]
}
string.json(中文)
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "像素转换"
},
{
"name": "pixel_introduce",
"value": "像素介绍"
},
{
"name": "pixel_conversion",
"value": "像素转换"
},
{
"name": "HarmonyHeiTi",
"value": "HarmonyHeiTi"
},
{
"name": "HarmonyHeiTi_Medium",
"value": "HarmonyHeiTi-Medium"
},
{
"name": "font_desc",
"value": "这是一段为%dfp的文字"
},
{
"name": "notice",
"value": "lpx与px之间的转换,需要根据实际情况设置designWidth"
},
{
"name": "px_unit",
"value": "屏幕物理像素单位。"
},
{
"name": "vp_unit",
"value": "屏幕密度相关像素,根据屏幕像素密度转换为屏幕物理像素。"
},
{
"name": "lpx_unit",
"value": "视窗逻辑像素单位,lpx单位为实际屏幕宽度与逻辑宽度(通过designWidth配置)的比值。"
},
{
"name": "fp_unit",
"value": "字体像素,与vp类似,随系统字体大小设置变化。"
},
{
"name": "vp_desc",
"value": "像素密度为160dpi的设备上1vp=1px,1vp对应的物理屏幕像素=(屏幕像素密度/160)px "
},
{
"name": "fp_desc",
"value": "默认情况下与vp相同,即1vp=1fp,如果用户手动调整了系统字体,scale为缩放比例,设置后的字体大小(单位fp) = 设置前的字体大小 * scale"
}
]
}
常量
// ets/common/constants/Constants.ets
export default class Constants {
static readonly FULL_PERCENT: string = '100%'
static readonly PIXEL_CONVERSION: string = '像素转换'
static readonly PIXEL_INTRODUCTION: string = '像素介绍'
static readonly INTRODUCTION_PAGE_URL: string = 'pages/IntroductionPage'
static readonly CONVERSION_PAGE_URL: string = 'pages/ConversionPage'
static readonly INDEX_PAGE_TAG: string = 'IndexPage push error '
static readonly TITLE_FONT_WEIGHT: number = 500
static readonly LABEL_FONT_WEIGHT: number = 400
static readonly COLUMN_SPACE: number = 24
static readonly ITEM_PADDING: number = 12
static readonly LARGE_FONT_SIZE: number = 24
static readonly SMALL_FONT_SIZE: number = 14
static readonly VP_SIZE: number = 60
static readonly PIXEL_WIDTH: number = 200
}
Logger
// ets/common/utils/Logger.ets
import { hilog } from '@kit.PerformanceAnalysisKit'
const LOGGER_PREFIX: string = 'Pixel Conversion'
class Logger {
private domain: number
private prefix: string
private format: string = '%{public}s, %{public}s'
constructor(prefix: string = '', domain: number = 0xFF00) {
this.prefix = prefix
this.domain = domain
}
debug(...args: string[]): void {
hilog.debug(this.domain, this.prefix, this.format, args)
}
info(...args: string[]): void {
hilog.info(this.domain, this.prefix, this.format, args)
}
warn(...args: string[]): void {
hilog.warn(this.domain, this.prefix, this.format, args)
}
error(...args: string[]): void {
hilog.error(this.domain, this.prefix, this.format, args)
}
}
export default new Logger(LOGGER_PREFIX)
四、首页面
// ets/pages/Index.ets
import { router } from '@kit.ArkUI'
import Constants from '../common/constants/Constants'
import Logger from '../common/utils/Logger'
@Entry
@Component
struct IndexPage {
jumpPage(url: string) {
router.pushUrl({ url })
.catch((error: Error) => {
Logger.error(Constants.INDEX_PAGE_TAG, JSON.stringify(error));
});
}
build() {
Column({ space: Constants.COLUMN_SPACE }) {
Button($r('app.string.pixel_introduce'))
.height($r('app.float.btn_height'))
.width(Constants.FULL_PERCENT)
.backgroundColor($r('app.color.blue_background'))
.onClick((): void => this.jumpPage(Constants.INTRODUCTION_PAGE_URL))
Button($r('app.string.pixel_conversion'))
.height($r('app.float.btn_height'))
.width(Constants.FULL_PERCENT)
.backgroundColor($r('app.color.blue_background'))
.onClick((): void => this.jumpPage(Constants.CONVERSION_PAGE_URL))
}
.backgroundColor($r('app.color.page_background'))
.justifyContent(FlexAlign.Center)
.padding(Constants.COLUMN_SPACE)
.width(Constants.FULL_PERCENT)
.height(Constants.FULL_PERCENT)
}
}
五、像素介绍页面
// ets/viewmodel/IntroductionItem.ets
export default class IntroductionItem {
name: string
title: Resource | string
subTitle: Resource | string
value: string
smallFontSize: number
largeFontSize: number
constructor(name?: string, title?: Resource | string, subTitle?: Resource | string, value?: string,
smallFontSize?: number, largeFontSize?: number) {
this.name = name ? name : ''
this.title = title ? title : ''
this.subTitle = subTitle ? subTitle : ''
this.value = value ? value : ''
this.smallFontSize = smallFontSize ? smallFontSize : 0
this.largeFontSize = largeFontSize ? largeFontSize : 0
}
}
// ets/viewmodel/InstroductionViewModel.ets
import Constants from '../common/constants/Constants'
import IntroductionItem from './IntroductionItem'
class IntroductionViewModel {
getIntroductionList() {
let introductionItems = INTRODUCE_LIST
return introductionItems;
}
}
const INTRODUCE_LIST: IntroductionItem[] = [
new IntroductionItem('px', $r('app.string.px_unit'), '', Constants.PIXEL_WIDTH + 'px', 0, 0),
new IntroductionItem('vp', $r('app.string.vp_unit'), $r('app.string.vp_desc'), Constants.PIXEL_WIDTH + 'vp', 0, 0),
new IntroductionItem('lpx', $r('app.string.lpx_unit'), '', Constants.PIXEL_WIDTH + 'lpx', 0, 0),
new IntroductionItem('fp', $r('app.string.fp_unit'), $r('app.string.fp_desc'), '', Constants.SMALL_FONT_SIZE,
Constants.LARGE_FONT_SIZE)
]
let introductionViewModel = new IntroductionViewModel()
export default introductionViewModel as IntroductionViewModel
// ets/views/IntroductionComponent.ets
import Constants from '../common/constants/Constants'
import IntroductionItem from '../viewmodel/IntroductionItem'
@Extend(Text) function titleTextStyle() {
.fontColor($r('app.color.title_font'))
.fontFamily($r('app.string.HarmonyHeiTi_Medium'))
.fontWeight(Constants.TITLE_FONT_WEIGHT)
}
@Component
export default struct IntroduceItemComponent {
model: IntroductionItem = new IntroductionItem()
build() {
Column() {
Text(this.model.name)
.titleTextStyle()
.fontSize($r('app.float.name_font_size'))
Text(this.model.title)
.titleTextStyle()
.fontSize($r('app.float.title_font_size'))
.fontFamily($r('app.string.HarmonyHeiTi'))
.lineHeight($r('app.float.desc_line_height'))
.margin({ top: $r('app.float.desc_margin_top') })
.fontWeight(Constants.LABEL_FONT_WEIGHT)
if (this.model.subTitle) {
Text(this.model.subTitle)
.titleTextStyle()
.opacity($r('app.float.label_opacity'))
.lineHeight($r('app.float.subtitle_line_height'))
.fontSize($r('app.float.subtitle_font_size'))
.fontFamily($r('app.string.HarmonyHeiTi'))
.margin({ top: $r('app.float.subtitle_margin_top') })
.fontWeight(Constants.LABEL_FONT_WEIGHT)
}
if (this.model.value.length > 0) {
Text(this.model.value)
.titleTextStyle()
.fontColor($r('app.color.item_background'))
.fontSize($r('app.float.name_font_size'))
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.blue_background'))
.height($r('app.float.value_height'))
.width(this.model.value)
.borderRadius($r('app.float.value_border_radius'))
.margin({ top: $r('app.float.item_padding') })
} else {
Column() {
Text($r('app.string.font_desc', this.model.smallFontSize))
.titleTextStyle()
.fontSize(this.model.smallFontSize)
Text($r('app.string.font_desc', this.model.largeFontSize))
.titleTextStyle()
.fontSize(this.model.largeFontSize)
.margin({ top: $r('app.float.title_margin_top') })
}
.alignItems(HorizontalAlign.Start)
.backgroundColor($r('app.color.font_background'))
.width(Constants.FULL_PERCENT)
.borderRadius($r('app.float.notice_border_radius'))
.padding($r('app.float.item_padding'))
.margin({ top: $r('app.float.item_padding') })
}
}
.alignItems(HorizontalAlign.Start)
.width(Constants.FULL_PERCENT)
.padding($r('app.float.item_padding'))
.borderRadius($r('app.float.item_border_radius'))
.backgroundColor($r('app.color.item_background'))
}
}
// ets/pages/IntroductionPage.ets
import Constants from '../common/constants/Constants'
import IntroductionItem from '../viewmodel/IntroductionItem'
import IntroduceItemComponent from '../views/IntroductionItemComponent'
import IntroductionViewModel from '../viewmodel/IntroductionViewModel'
@Entry
@Component
struct IntroductionPage {
build() {
Column() {
Navigation() {
List({ space: Constants.ITEM_PADDING }) {
ForEach(IntroductionViewModel.getIntroductionList(), (item: IntroductionItem) => {
ListItem() {
IntroduceItemComponent({ model: item })
}
.padding({
left: $r('app.float.item_padding'),
right: $r('app.float.item_padding')
})
})
}
.width(Constants.FULL_PERCENT)
.height(Constants.FULL_PERCENT)
}
.titleMode(NavigationTitleMode.Mini)
.title(Constants.PIXEL_INTRODUCTION)
}
.backgroundColor($r('app.color.page_background'))
.width(Constants.FULL_PERCENT)
.height(Constants.FULL_PERCENT)
}
}
六、像素转换页面
// ets/viewmodel/ConversionItem.ets
export default class ConversionItem {
title: string
subTitle: string
value: number = 0
conversionTitle: string
conversionSubTitle: string
conversionValue: number
notice?: Resource | string
constructor(title?: string, subTitle?: string, value?: number, conversionTitle?: string, conversionSubTitle?: string,
conversionValue?: number, notice?: Resource | string) {
this.title = title ? title : ''
this.subTitle = subTitle ? subTitle : ''
this.value = value ? value : 0
this.conversionTitle = conversionTitle ? conversionTitle : ''
this.conversionSubTitle = conversionSubTitle ? conversionSubTitle : ''
this.conversionValue = conversionValue ? conversionValue : 0
this.notice = notice ? notice : ''
}
}
// ets/viewmodel/ConversionViewModel.ets
import Constants from '../common/constants/Constants'
import ConversionItem from './ConversionItem'
class ConversionViewModel {
getConversionList() {
let conversionItems = CONVERSION_LIST;
return conversionItems;
}
}
export const CONVERSION_LIST: ConversionItem[] = [
new ConversionItem('vp > px', `vp2px(${Constants.VP_SIZE})`, vp2px(Constants.VP_SIZE), 'px > vp',`px2vp(${Constants.VP_SIZE})`, px2vp(Constants.VP_SIZE)),
new ConversionItem('fp > px',`fp2px(${Constants.VP_SIZE})`,fp2px(Constants.VP_SIZE),'px > fp',`px2fp(${Constants.VP_SIZE})`,px2fp(Constants.VP_SIZE)),
new ConversionItem('lpx > px',`lpx2px(${Constants.VP_SIZE})`,lpx2px(Constants.VP_SIZE),'px > lpx',`px2lpx(${Constants.VP_SIZE})`,px2lpx(Constants.VP_SIZE),$r('app.string.notice'))
]
let conversionViewModel = new ConversionViewModel()
export default conversionViewModel as ConversionViewModel
// ets/views/ConversionItemComponent.ets
import Constants from '../common/constants/Constants'
import ConversionItem from '../viewmodel/ConversionItem'
@Extend(Text) function descTextStyle() {
.fontColor($r('app.color.title_font'))
.fontSize($r('app.float.title_font_size'))
.fontFamily($r('app.string.HarmonyHeiTi'))
.lineHeight($r('app.float.desc_line_height'))
.fontWeight(Constants.LABEL_FONT_WEIGHT)
.margin({ top: $r('app.float.desc_margin_top') })
}
@Extend(Text) function titleTextStyle() {
.fontColor($r('app.color.title_font'))
.fontSize($r('app.float.name_font_size'))
.fontFamily($r('app.string.HarmonyHeiTi_Medium'))
.fontWeight(Constants.TITLE_FONT_WEIGHT)
}
@Styles function blueStyle() {
.backgroundColor($r('app.color.blue_background'))
.height($r('app.float.value_height'))
.borderRadius($r('app.float.value_border_radius'))
.margin({ top: $r('app.float.blue_margin_top') })
}
@Component
export default struct ConversionItemComponent {
model: ConversionItem = new ConversionItem()
build() {
Column() {
Text(this.model.title)
.titleTextStyle()
.margin({ top: $r('app.float.title_margin_top') })
Text(this.model.subTitle)
.descTextStyle()
.opacity($r('app.float.label_opacity'))
Row()
.blueStyle()
.width(this.model.value)
Text(this.model.conversionTitle)
.titleTextStyle()
.margin({ top: $r('app.float.item_margin_top') })
Text(this.model.conversionSubTitle)
.descTextStyle()
.opacity($r('app.float.label_opacity'))
Row()
.blueStyle()
.width(this.model.conversionValue)
if (this.model.notice) {
Text(this.model.notice)
.descTextStyle()
.fontColor($r('app.color.notice_font'))
}
}
.alignItems(HorizontalAlign.Start)
.width(Constants.FULL_PERCENT)
.padding($r('app.float.item_padding'))
.borderRadius($r('app.float.item_border_radius'))
.backgroundColor($r('app.color.item_background'))
}
}
// ets/pages/ConversionPage.ets
import Constants from '../common/constants/Constants'
import ConversionItemComponent from '../views/ConversionItemComponent'
import ConversionItem from '../viewmodel/ConversionItem'
import ConversionViewModel from '../viewmodel/ConversionViewModel'
@Entry
@Component
struct ConversionPage {
build() {
Column() {
Navigation() {
List({ space: Constants.ITEM_PADDING }) {
ForEach(ConversionViewModel.getConversionList(), (item: ConversionItem) => {
ListItem() {
ConversionItemComponent({ model: item })
}
.padding({
left: $r('app.float.item_padding'),
right: $r('app.float.item_padding')
})
})
}
.width(Constants.FULL_PERCENT)
.height(Constants.FULL_PERCENT)
}
.titleMode(NavigationTitleMode.Mini)
.title(Constants.PIXEL_CONVERSION)
}
.backgroundColor($r('app.color.page_background'))
.width(Constants.FULL_PERCENT)
.height(Constants.FULL_PERCENT)
}
}
✋ 需要参加鸿蒙认证的请点击 鸿蒙认证链接