HarmonyOS 鸿蒙Next实现沉浸式效果
第5篇:HarmonyOS 鸿蒙Next实现沉浸式效果(鸿蒙应用0-1开发)
<markdown _ngcontent-ioa-c237="" class="markdownPreContainer">
实现沉浸式效果
上一篇我们实现拦截系统返回的弹窗时,遗留了个问题,那就是顶部状态栏和底部导航栏并没有覆盖到。而这一节通过设置全屏来规避这个问题,而正巧的是实现沉浸式也是需要全屏处理。首先看看效果:
- 第1篇:鸿蒙APP开发怎么样开始?
- 第2篇:如何使用Navigation+tab搭建路由页面?
- 第3篇:手把手教你如何实现对Navigation路由框架的封装!
- 第4篇:对话框是每个项目的基础,那么禁止系统返回的对话框应该如何实现呢?
1.实现的关键流程
1.1.实现全屏
实现全屏其实也有两种方案
- 第一种方式:设置导航栏、状态栏不显示,这种方式会直接把状态栏的内容直接去掉,比如电量、信号、通知消息等等。如下:
let names: Array<'status' | 'navigation'> = [];
windowClass.setWindowSystemBarEnable(names, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting the system bar to be visible.');
});
- 因此,我们采用第二种方式:设置窗口为全屏布局,配合设置导航栏、状态栏的透明度、背景/文字颜色及高亮图标等属性,与主窗口显示保持协调一致。
let isLayoutFullScreen = true;
windowClass.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting the window layout to full-screen mode.');
});
let sysBarProps: window.SystemBarProperties = {
statusBarColor: '#ff00ff',
navigationBarColor: '#00ff00',
// 以下两个属性从API Version 8开始支持
statusBarContentColor: '#ffffff',
navigationBarContentColor: '#ffffff'
};
windowClass.setWindowSystemBarProperties(sysBarProps, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in setting the system bar properties.');
});
})
1.2.获取状态栏和导航栏高度
在EntryView
中:
aboutToAppear(): void { window.getLastWindow(getContext()).then((lastWindow) => { let areas = lastWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);//以状态栏为避让 const statusHeight = px2vp(areas.topRect.height);
areas = lastWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);<span class="hljs-comment"><span class="hljs-comment">// 以导航条避让</span></span> <span class="hljs-keyword"><span class="hljs-keyword">const</span></span> navHeight = px2vp(areas.bottomRect.height); <span class="hljs-comment"><span class="hljs-comment">//保存到到全局变量</span></span> AppStorage.setOrCreate(<span class="hljs-string"><span class="hljs-string">'statusHeight'</span></span>, statusHeight); AppStorage.setOrCreate(<span class="hljs-string"><span class="hljs-string">'navHeight'</span></span>, navHeight); });
}
1.3.设置状态栏和导航栏的占位
- 上面我们通过
AppStorage.setOrCreate
把高度保存起来,现在我们在MainPage
和HomePage
页面取出来:
[@StorageProp](/user/StorageProp)('statusHeight') statusHeight: number = 0;
[@StorageProp](/user/StorageProp)('navHeight') navHeight: number = 0;
- 取出来后,我们根据高度设置占坑高度,如在
MainPage
中:
build() { Column() { Stack() { if (this.selectIndex === 0) { HomePage() } else if (this.selectIndex === 1) { ToolPage() } else if (this.selectIndex === 2) { MyPage() } } .width('100%') .layoutWeight(1)
<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.tabBuilder() <span class="hljs-comment"><span class="hljs-comment">//TODO ---》把底部导航栏的高度露出来</span></span> Line().height(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.navHeight).visibility(Visibility.Hidden) } .height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>)
}
1.4.通过设置状态栏和标题栏颜色,从而实现沉浸式效果
HomePage
页面的完整代码:
/* * [@Desc](/user/Desc): * [@Author](/user/Author): qincji * [@Date](/user/Date): 2024/6/12 */ import { RouterNav, RouterPage } from '[@common](/user/common)/router/Index'; import { HintParm } from '[@common](/user/common)/dialog/Index'; import { log } from '[@common](/user/common)/utils';
const TAG = ‘HomePage’;
@Component export struct HomePage { @State value: string = ‘’; @StorageProp(‘statusHeight’) statusHeight: number = 0; @StorageProp(‘navHeight’) navHeight: number = 0;
aboutToAppear(): void { log.i(TAG,
获取系统状态栏和导航栏高度: ${this.statusHeight} | ${this.navHeight}
) }build() { Column() { //沉浸式效果 Column() { //把顶部状态栏的高度露出来 Line().height(this.statusHeight).visibility(Visibility.Hidden) Text(“标题”) .layoutWeight(1) .textAlign(TextAlign.Center) .fontSize(16) .fontWeight(FontWeight.Medium) .fontColor(Color.White) } .width(‘100%’) .linearGradient({ angle: 0, // 0点方向顺时针旋转为正向角度,线性渐变起始角度的默认值为180° colors: [ [’#74C678’, 0.0], // 颜色断点1的颜色和比重,对应组件在180°方向上的起始位置 [’#266B29’, 1.0],// 颜色断点2的颜色和比重,对应组件在180°方向上的终点位置 ] }) .height(this.statusHeight + 50)
Text(<span class="hljs-string"><span class="hljs-string">'这是首页'</span></span>).fontSize(<span class="hljs-number"><span class="hljs-number">35</span></span>).margin({ top: <span class="hljs-number"><span class="hljs-number">100</span></span> }) Text(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.value).fontSize(<span class="hljs-number"><span class="hljs-number">35</span></span>) Button(<span class="hljs-string"><span class="hljs-string">'对话框'</span></span>) .onClick(() => { <span class="hljs-keyword"><span class="hljs-keyword">const</span></span> parm: HintParm = { content: <span class="hljs-string"><span class="hljs-string">"Command Line Tools集合了HarmonyOS应用开发所用到的系列工具,包括代码检查codelinter、三方库包管理ohpm、命令行解析hstack、编译构建hvigorw。"</span></span>, showNo: <span class="hljs-keyword"><span class="hljs-keyword">false</span></span>, outsideCancel: <span class="hljs-keyword"><span class="hljs-keyword">false</span></span>, pressBackCancel: <span class="hljs-keyword"><span class="hljs-keyword">false</span></span>, alignment: Alignment.Center, noTitle: <span class="hljs-keyword"><span class="hljs-keyword">true</span></span>, okMsg: <span class="hljs-string"><span class="hljs-string">"同意,并继续!"</span></span>, onOk: () => { <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.value = <span class="hljs-string"><span class="hljs-string">"点击了确定!"</span></span> } } RouterNav.push(RouterPage.HINT_DIALOG, parm) }) } .width(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) .height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>)
} }
2.自定义沉浸式头部组件
根据以往的操作,新建module:
common/component
,接着在entry和login模块进行导入。新建组件:
Header
,详细代码:
/* * [@Desc](/user/Desc): 沉浸式状态栏和标题栏的设置 * [@Author](/user/Author): qincji * [@Date](/user/Date): 2024/6/23 */ [@Component](/user/Component) export struct Header { [@Require](/user/Require) [@Prop](/user/Prop) title: string | Resource; //标题 onKeyBack?: () => void; //监听返回事件,如果不设置则隐藏返回键 [@BuilderParam](/user/BuilderParam) rightLayout?: () => void; //自定义的右边布局 titleBarHeight: Length = 45; //标题栏高度 titleSize: number | string | Resource = '18fp'; //标题字体大小 titleAttrModifier: AttributeModifier<TextAttribute> = {}; //标题控件的样式 bgTopColor: ResourceColor = '#74C678'; //状态栏和标题栏背景 顶部颜色 bgBottomColor: ResourceColor = '#266B29'; //状态栏和标题栏背景 底部颜色 titleColor: ResourceColor = Color.White; //标题字体颜色 [@StorageProp](/user/StorageProp)('statusHeight') statusHeight: number = 0; //状态栏高度
build() { Stack() { RelativeContainer() { Text(this.title) .fontSize(this.titleSize) .width(‘50%’) .height(‘100%’) .fontColor(this.titleColor) .fontWeight(FontWeight.Medium) .ellipsisMode(EllipsisMode.END) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(1) .textAlign(TextAlign.Center) .alignRules({ middle: { anchor: “container”, align: HorizontalAlign.Center }, }) .id(“i1”) .attributeModifier(this.titleAttrModifier)
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.onKeyBack) { Image($r(<span class="hljs-string"><span class="hljs-string">'app.media.ic_back'</span></span>)) .height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) .padding({ left: <span class="hljs-number"><span class="hljs-number">16</span></span>, top: <span class="hljs-number"><span class="hljs-number">11</span></span>, bottom: <span class="hljs-number"><span class="hljs-number">11</span></span>, right: <span class="hljs-number"><span class="hljs-number">11</span></span> }) .fillColor(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.titleColor) .objectFit(ImageFit.Contain) .alignRules({ left: { anchor: <span class="hljs-string"><span class="hljs-string">"__container__"</span></span>, align: HorizontalAlign.Start }, }) .id(<span class="hljs-string"><span class="hljs-string">"i2"</span></span>) .onClick(() => { <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.onKeyBack?.() }) } <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.rightLayout) { Row() { <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.rightLayout?.() } .height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) .justifyContent(FlexAlign.End) .alignRules({ right: { anchor: <span class="hljs-string"><span class="hljs-string">"__container__"</span></span>, align: HorizontalAlign.End }, }) .id(<span class="hljs-string"><span class="hljs-string">"i3"</span></span>) } } .width(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) .height(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.titleBarHeight) } .width(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) .padding({ top: <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.statusHeight }) .backgroundColor(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.bgTopColor) .linearGradient({ angle: <span class="hljs-number"><span class="hljs-number">0</span></span>, <span class="hljs-comment"><span class="hljs-comment">// 0点方向顺时针旋转为正向角度,线性渐变起始角度的默认值为180°</span></span> colors: [ [<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.bgTopColor, <span class="hljs-number"><span class="hljs-number">0.0</span></span>], <span class="hljs-comment"><span class="hljs-comment">// 颜色断点1的颜色和比重,对应组件在180°方向上的起始位置</span></span> [<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.bgBottomColor, <span class="hljs-number"><span class="hljs-number">1.0</span></span>],<span class="hljs-comment"><span class="hljs-comment">// 颜色断点2的颜色和比重,对应组件在180°方向上的终点位置</span></span> ] })
} }
- 在各个页面使用,如登录页完整代码:
import { RouterNav, RouterPage } from '[@common](/user/common)/router'; import { Header } from '[@common](/user/common)/component';
@Component export struct LoginPage { @State result: string = “”; @State register: string = ‘注册’;
build() { NavDestination() { Column() { Header({ title: ‘登录’, onKeyBack: () => { RouterNav.pop() }, //TODO - 注意:写成 rightLayout: this.rightRegisterBuilder 会调不到本类的属性 rightLayout: () => { this.rightRegisterBuilder() } }) Text(‘这是登录页面, 有NavDestination’).fontSize(35) Text(
接收到的数据:${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.result}
).fontSize(35)Button(<span class="hljs-string"><span class="hljs-string">'返回--》给点数据'</span></span>) .onClick(() => { <span class="hljs-keyword"><span class="hljs-keyword">const</span></span> record: Record<<span class="hljs-built_in"><span class="hljs-built_in">string</span></span>, Object> = { <span class="hljs-string"><span class="hljs-string">'from'</span></span>: <span class="hljs-string"><span class="hljs-string">'login/login'</span></span>, <span class="hljs-string"><span class="hljs-string">'text'</span></span>: <span class="hljs-string"><span class="hljs-string">"登录给你的"</span></span>, <span class="hljs-string"><span class="hljs-string">'age'</span></span>: <span class="hljs-number"><span class="hljs-number">19</span></span>, } RouterNav.pop(record) }) } .width(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) .height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) } .onReady(cxt => { <span class="hljs-keyword"><span class="hljs-keyword">const</span></span> record = cxt.pathInfo.param as Record<<span class="hljs-built_in"><span class="hljs-built_in">string</span></span>, object>; <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.result = JSON.stringify(record); }) .mode(NavDestinationMode.STANDARD) .hideTitleBar(<span class="hljs-keyword"><span class="hljs-keyword">true</span></span>)
}
@Builder private rightRegisterBuilder() { Text(this.register).fontSize(13).margin({ right: 16 }).fontColor(Color.White).onClick(() => { RouterNav.replace(RouterPage.REGISTER) }) } }
@Builder function getPage(_value: object): void { LoginPage(); }
RouterNav.registerPage(RouterPage.LOGIN, wrapBuilder(getPage))
到这里,所有的内容已经结束了!本章的完整源码已经上传到gitee了:鸿蒙应用0-1开发。
更多关于HarmonyOS 鸿蒙Next实现沉浸式效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS 鸿蒙Next实现沉浸式效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
关于HarmonyOS 鸿蒙Next实现沉浸式效果的问题,以下是一些专业解答:
在HarmonyOS中,实现沉浸式效果主要需调整状态栏、应用界面和导航条的显示效果。具体步骤如下:
- 设置窗口全屏布局:通过调用
setWindowLayoutFullScreen()
方法,将布局系统调整为全屏布局,使界面元素延伸到状态栏和导航条区域。 - 获取并避让布局遮挡区域:使用
getWindowAvoidArea()
方法获取状态栏和导航条的高度,然后对界面元素进行避让处理,避免被遮挡。 - 设置系统栏属性:可自定义状态栏和导航栏的背景颜色、文字颜色以及图标的高亮状态,以与界面元素相匹配,实现沉浸式效果。
请注意,实现沉浸式效果时,需确保界面元素不会覆盖到可交互区域,如导航条底部区域,以保持良好的用户体验。
HarmonyOS 鸿蒙Next视频详解:https://www.itying.com/category-93-b0.html。