《鸿蒙纪元》 是 张风捷特烈 计划打造的一套 HarmonyOS 开发系列教程合集。致力于创作优质的鸿蒙原生学习资源,帮助开发者进入纯血鸿蒙的开发之中。本系列的所有代码将开源在 HarmonyUnit 项目中:
github
: github.com/toly1994328…
gitee
: gitee.com/toly1994328…
本文是《鸿蒙纪·梦始卷》 的第三章,上一篇我们搭建了一个简单的功能应用,本篇将基于这个小案例,继续优化界面表现。本文你将学到:
[1]
. 学会资源文件的使用,包括图片、字符串、颜色、数字等。[2]
. 学会沉浸状态导航栏,实现全屏布局的方案。[3]
. 了解鸿蒙开发时文字、视图尺寸单位,统一配置常量资源。
一、资源文件的使用
资源文件在 entry/src/main/resources
文件夹下:
官方文档中对资源目录结构有详细的介绍,目前我们主要使用 base
的 media
文件夹中放置媒体数据,比如图片、音频;在 element
文件夹中放置字符串、颜色等常量资源。
1. 图片文件的使用
ArkUI 中通过 Image 组件展示图片,它可以支持常规的图片格式,比如 png、jpg、webp、gif 等,也可以直接支持 svg
的图像资源:。如下所示,将 logo.webp
和 more.svg
放到 media 文件夹下:
现在,我们的目标是将这两个图片资源放置在计数器 AppBar 的两侧,如下所示:
上一篇中,我们通过插槽的方式,将 AppBar 左右组件交由外部传入,想要更改左侧展示内容,只需要在 Index 组件的 leading
构建方法中修改即可:
这里通过 Button 组件占据 36*36
的尺寸,内部放置 Image 组件,尺寸是 30*30
;media 中的图片资源通过 $r('app.media.名称')
来访问:
---->[Index.ets#Index]----
@Builder
leading() {
Button(){
Image($r('app.media.logo')).width(30).height(30)
}
.width(36).height(36)
.backgroundColor(Color.Transparent)
}
同理,AppBar 尾部的组件可以通过修改 tailing
组件进行构建;另外 svg 图片可以通过 fillColor
修改颜色值,这相比于普通图片更加灵活:
@Builder
tailing() {
Button(){
Image($r('app.media.more'))
.width(24).height(24)
.fillColor(Color.White)
}
.width(36).height(36)
.backgroundColor(Color.Transparent)
}
2.常量数值资源
对于一些全局的常量资源,我们可以统一配置在资源中,方便统一维护,比如字体大小、颜色、字符串等。防止在 element
文件夹下,其中:
string.json
: 放置字符串资源color.json
: 放置颜色资源float.json
: 放置数值资源
比如计数器中,按钮颜色、AppBAr 颜色都是一样的,我们想要定义一个主题色,方便统一维护。可以在 color.json 中增加一个 theme_color
的元素,指定对应的值, 在代码中通过 $r
访问资源设置即可
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
},
{
"name": "theme_color",
"value": "#317bd4"
}
]
}
这样,color 中的 theme_color 修改后,就可以让所有使用到它的地方发生变化:
#ff5a5f | #ff5a5f |
---|---|
3. 了解像素单位
对于需要统一维护尺寸、字符串,字符串和数值的资源也是同理。比如文字大小、边距间隔值、应用名称等。这里简单介绍一下像素相关的单位。如下四个分别是使用 18px
、18vp
、 18数字
、18fp
设置文字大小的效果:
我们知道屏幕是由一个个像素点构成的, px
单位就是绝对的像素数字。
fp
表示 虚拟像素 (virtual pixel)
是一台设备针对应用而言所具有的虚拟尺寸, 它可在任何屏幕上缩放以具有统一的尺寸体量。从二三两行可以看出,在代码中,数值本身就是虚拟像素值。
fp
表示 字体像素 (font pixel)
默认情况下与 vp 相同,即默认情况下 1 fp = 1vp。所以三四行表现效果相同。但如果用户在设置中选择了更大的字体,字体的实际显示大小就会在 vp 的基础上乘以 scale 系数,即 1 fp = 1 vp * scale。
所以对于文字来说,一般取用 fp 单位,其他尺寸可以直接使用数值。
Text('鸿蒙纪元 HarmonyUnit: 18px').fontSize('18px')
Text('鸿蒙纪元 HarmonyUnit: 18vp').fontSize('18vp')
Text('鸿蒙纪元 HarmonyUnit: 18').fontSize(18)
Text('鸿蒙纪元 HarmonyUnit: 18fp').fontSize('18fp')
通过 $r('app.float.xxx')
可以访问资源中提供的尺寸值,如下所示为计数器的描述和数值,设置文字大小:
{
"float": [
{
"name": "counter_value_size",
"value": "36fp"
},
{
"name": "counter_desc_size",
"value": "18fp"
},
{
"name": "app_bar_title_size",
"value": "20fp"
}
]
}
对于这种数值资源,IDE 也会自动展示对应的数值,也保证一定的代码可读性:
4. 国际化资源配置
一般应用程序中展示的资源字符串需要适应系统中不同的语言,鸿蒙开发中提供了资源字符串国际化的方案。在项目中有对应语言的文件夹,在其中的 string.json
中定义映射关系,就可以支持国际化。
---->[src/main/resources/base/string.json]----
{
"name": "counter_title",
"value": "计数器"
},
{
"name": "counter_tips",
"value": "下面是你点击按钮的次数:"
}
---->[src/main/resources/en_US/element/string.json]----
{
"name": "counter_title",
"value": "Counter"
},
{
"name": "counter_tips",
"value": "You have pushed the button this many times:"
}
---->[src/main/resources/zh_CN/element/string.json]----
{
"name": "counter_title",
"value": "计数器"
},
{
"name": "counter_tips",
"value": "下面是你点击按钮的次数:"
}
如下所示,如果希望在 系统语言
切换时,应用程序可以展示不同的字符串资源。只要在不同语言的文件夹中提供字符串映射即可,如果当前系统语言没有支持,会使用 base
中的资源。通过 $r('app.string.xxx')
访问对应的字符串:
注:资源对象类型是 Resource
,可以将 AppBar 组件中 title 属性类型设置为 string | Resource
,表示该属性既可以设置为 string 也可以设置为 Resource 对象:
@Component
struct AppBar {
private title: string | Resource = '';
系统中文系统 | 系统英文语言 |
---|---|
这里提交一个小里程碑 计数器-v4-资源使用。
二、沉浸状态栏与全屏展示
上面的截图可以看出,应用会有顶部的标题栏
和底部导航栏
,导致应用并没有全屏展示,下面就来看一下如何处理。参考官方文档 《开发应用沉浸式效果》
1. 窗口全屏处理
首先我们需要在窗口启动时,将窗口设置为全屏。这个操作需要在 entry/src/main/ets/entryability/EntryAbility.ets
文件中处理。 onWindowStageCreate
回调可以监听到窗口创建的时机:
---->[ets/entryability/EntryAbility.ets]----
let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口
// 1. 设置窗口全屏
let isLayoutFullScreen = true;
windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {
console.info('Succeeded in setting the window layout to full-screen mode.');
}).catch((err: BusinessError) => {
console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
});
如果只是设置为全屏,那么顶部和底部的界面元素将会出现重叠的问题(左图)。我们应该获取区域的高度,让界面元素避让状态栏和底部导航栏:
状态栏遮挡 | 期望的效果 |
---|---|
2. 获取窗口状态栏和导航栏高度
还是在刚才的 EntryAbility 文件中,在窗口创建时可以获取顶部状态栏和底部导航栏的高度,通过 AppStorage
可以将对象在全局存储起来;另外可以监听 avoidAreaChange
回调,当避让区域发生变化时,也可以及时更新:
---->[ets/entryability/EntryAbility.ets]----
// 2. 获取布局避让遮挡的区域
let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例
let avoidArea = windowClass.getWindowAvoidArea(type);
let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例
avoidArea = windowClass.getWindowAvoidArea(type);
let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度
AppStorage.setOrCreate('topRectHeight', topRectHeight);
// 3. 注册监听函数,动态获取避让区域数据
windowClass.on('avoidAreaChange', (data) => {
if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
let topRectHeight = data.area.topRect.height;
AppStorage.setOrCreate('topRectHeight', topRectHeight);
} else if (data.type == window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
let bottomRectHeight = data.area.bottomRect.height;
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
}
});
3. 避让高度的获取和使用
顶部展示的组件是 AppBar,所以我们可以将避让的逻辑封装在 AppBar 中,如下所示,
[1]
: 通过@StorageProp('名称')
可以访问存储在全局的对象。[2]
: 然后让AppBar
的高度增加顶部的避让高度,并且内容距离上方有相应的内边距:[3]
: 获取的避让高度是像素值,需要通过 px2pv 转换成虚拟像素。
@Component
struct AppBar {
private title: string | Resource = '';
@StorageProp('topRectHeight')
topRectHeight: number = 0;
/// 略同...
build() {
/// 略同...
.height(56+ px2vp(this.topRectHeight))
.padding({ left: 8, right: 8,top: px2vp(this.topRectHeight) })
.justifyContent(FlexAlign.SpaceBetween)
}
}
同理,底部区域的避让,可以让整体距离底部指定高度:
0 | 6 |
---|---|
这里提交一个小里程碑 计数器-v5-沉浸标题栏。大家可以把这篇文章的知识点通过树形结构记录一下,下一篇开始时我会给出我的 ~
尾声
到这里,我们就了解了资源使用的方式,以及如何处理沉浸标题栏。后续将继续鸿蒙纪元的进程,通过一些有趣的小功能,体验和入门鸿蒙的开发,我们下次再见~
更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。