HarmonyOS鸿蒙Next中2in1设备HdsNavigation的titleBar会侵入WindowDecor
HarmonyOS鸿蒙Next中2in1设备HdsNavigation的titleBar会侵入WindowDecor 在EntryAbility中设置了
win.setWindowLayoutFullScreen(false)
在其他设备上HdsNavigation的titleBar的避让都正常,但在2in1设备中HdsNavigation的titleBar会侵入WindowDecor,如何解决




更多关于HarmonyOS鸿蒙Next中2in1设备HdsNavigation的titleBar会侵入WindowDecor的实战教程也可以访问 https://www.itying.com/category-93-b0.html
当设置win.setWindowDecorVisible(false)后WindowDecor自动下沉到内容区内,目前的规格没有主动避让会导致我在2in1设备上使用HdsNavigation的title时不管什么断点都会入侵到WindowDecor,具体情况可以看我发的截图。因为此问题无法解决,我现在已经采取放弃使用HdsNavigation的title,在每个页面上手搓了一个title出来。但尽管这样,通过手搓方式实现的title要实现HdsNavigation的title中的滚动模糊效果还是有些许麻烦的,且每个页面都需要逐一适配。所以如果可以,我想官方能实现对这个WindowDecor的高度进行避让(28vp)。
尊敬的开发者,您好!该功能正在规划中,还请关注后续版本,感谢您的理解与支持。
尊敬的开发者,您好!您的问题已复现,感谢您的反馈,问题正在加速处理中,还请关注后续版本,感谢您的理解与支持。
//EntryAbility
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
});
windowStage.getMainWindow((err:BusinessError,win)=>{
win.setWindowDecorVisible(false)
win.setWindowLayoutFullScreen(true)
})
}
//Index.ets
import { HdsNavigation, HdsNavigationTitleMode, HdsTabs,
ScrollEffectType } from '@hms.hds.hdsBaseComponent';
import { HomeView } from '../views/HomeView';
import { TestView } from '../views/TestView';
import { MineView } from '../views/MineView';
import { LengthMetrics, SymbolGlyphModifier } from '@kit.ArkUI';
import { HdsSideBar, HdsSideMenu, HdsSideMenuMainItem } from '@kit.UIDesignKit';
@Entry
@ComponentV2
struct Index {
@Local stack: NavPathStack = new NavPathStack();
@Local mainTitle: string = "我的设备";
@Local currentIndex:number=0
scroller: Scroller = new Scroller();
@Local sideBarWidth:string='100%'
listOptionsDefault?: HdsSideMenuMainItem[] = [
new HdsSideMenuMainItem({
symbol: new SymbolGlyphModifier($r('sys.symbol.doc_plaintext')),
label: '主页',
}),
new HdsSideMenuMainItem({
symbol: new SymbolGlyphModifier($r('sys.symbol.star')),
label: '测试',
}),
new HdsSideMenuMainItem({
symbol: new SymbolGlyphModifier($r('sys.symbol.lock')),
label: '设置',
})
]
@Builder
SideBarPanelBuilder() {
Column() {
Text('左侧侧边栏区')
HdsSideMenu({
items: this.listOptionsDefault,
selectedIndex: this.currentIndex,
$selectedIndex: (selectedIndex: number) => {
this.currentIndex = selectedIndex;
this.mainTitle=selectedIndex===0?'我的设备':selectedIndex===1?"测试":"我的"
},
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Transparent)
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#ff748573', 0.0], [Color.White, 1]]
})
}
//右侧内容区
@Builder
ContentPanelBuilder() {
if (this.currentIndex===0){
HomeView()
}else if (this.currentIndex===1) {
TestView()
}else if (this.currentIndex===2) {
MineView()
}
}
@BuilderParam contentBuilder: () => void = this.ContentPanelBuilder
@BuilderParam sideBarBuilder: () => void = this.SideBarPanelBuilder
build() {
HdsNavigation(this.stack){
HdsSideBar({
sideBarPanelBuilder: (): void => {
this.sideBarBuilder()
},
contentPanelBuilder: (): void => {
this.contentBuilder()
},
sideBarContainerType: SideBarContainerType.Embed,
isShowSideBar: true,
})
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#ff748573', 0.0], [Color.White, 1]]
})
}
.titleBar({
style: {
scrollEffectOpts: {
enableScrollEffect: true,
scrollEffectType: ScrollEffectType.GRADUAL_BLUR,
blurEffectiveStartOffset: LengthMetrics.vp(0),
blurEffectiveEndOffset: LengthMetrics.vp(20)
},
originalStyle: {
backgroundStyle: {
backgroundColor: Color.Transparent
},
contentStyle: {
titleStyle: { mainTitleColor: '#ffe2e2e2' }
}
},
scrollEffectStyle: {
backgroundStyle: {
backgroundColor: Color.Transparent
},
contentStyle: {
titleStyle: { mainTitleColor: '#ffe2e2e2' }
}
},
},
content: {
title: {
mainTitle: this.mainTitle
},
menu:{
value:[{
content:{
label:'设置',
icon:$r('sys.symbol.gearshape'),
isEnabled:true,
action:()=>{
this.stack.pushPathByName('SettingView',null,true)
}
}
}]
}
},
})
.systemBarStyle({ statusBarContentColor: '#ffe2e2e2' }, { statusBarContentColor: '#ffe2e2e2' })
.bindToScrollable([this.scroller])
.ignoreLayoutSafeArea()
.hideToolBar(true)
.titleMode(HdsNavigationTitleMode.MODAL)
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#ff748573', 0.0], [Color.White, 1]]
})
.navBarWidth(this.sideBarWidth)
}
}
开发者你好,我使用DevEco Studio 6.0.1 Release和对应API21版本的模拟器运行下面的代码未能复现您的问题。麻烦您补充以下信息:
1、复现代码(如最小复现demo); 2、版本信息(如:开发工具、手机系统版本信息);
import { HdsNavigation, HdsNavigationAttribute, HdsNavigationTitleMode, ScrollEffectType } from '@kit.UIDesignKit';
@Entry
@Component
struct Index {
@State pageIndex: number = 0;
@State toolItems: Array<ToolbarItem> = [
{
value: '首页',
icon: '',
action: () => {
this.pageIndex = 0
},
status: this.pageIndex == 0 ? ToolbarItemStatus.ACTIVE : ToolbarItemStatus.NORMAL
},
{
value: '媒体库',
icon: '',
action: () => {
this.pageIndex = 1
},
status: this.pageIndex == 1 ? ToolbarItemStatus.ACTIVE : ToolbarItemStatus.NORMAL
},
{
value: '设置',
icon: '',
action: () => {
this.pageIndex = 2
},
status: this.pageIndex == 2 ? ToolbarItemStatus.ACTIVE : ToolbarItemStatus.NORMAL
}
]
build() {
HdsNavigation() {
}
.height('100%')
.width('100%')
.hideBackButton(true)
.titleBar({
style: {
scrollEffectOpts: {
enableScrollEffect: true,
scrollEffectType: ScrollEffectType.COMMON_BLUR
}
},
content: {
title: {
mainTitle: '我的设备'
},
menu: {
value: [
{
content: {
action: () => {
}
}
}
]
}
}
})
.titleMode(HdsNavigationTitleMode.FULL)
.toolbarConfiguration(this.toolItems, {
backgroundColor:'#00ffffff',
backgroundBlurStyle: BlurStyle.BACKGROUND_ULTRA_THICK,
backgroundBlurStyleOptions: {
policy: BlurStyleActivePolicy.ALWAYS_ACTIVE
},
hideItemValue: false,
barStyle: BarStyle.STACK
})
}
}
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
import numpy as np
# 定义数据集类
class CustomDataset(Dataset):
def __init__(self, data, labels):
self.data = data
self.labels = labels
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
return self.data[idx], self.labels[idx]
# 定义简单神经网络模型
class SimpleNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, output_size)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
# 生成模拟数据
def generate_data(num_samples=1000, input_size=10):
data = np.random.randn(num_samples, input_size).astype(np.float32)
labels = np.random.randint(0, 2, size=(num_samples,)).astype(np.int64)
return data, labels
# 训练函数
def train_model(model, dataloader, criterion, optimizer, num_epochs=10):
model.train()
for epoch in range(num_epochs):
running_loss = 0.0
for inputs, labels in dataloader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch {epoch+1}/{num_epochs}, Loss: {running_loss/len(dataloader):.4f}")
# 主函数
def main():
# 设置随机种子
torch.manual_seed(42)
np.random.seed(42)
# 生成数据
data, labels = generate_data()
dataset = CustomDataset(data, labels)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 初始化模型、损失函数和优化器
input_size = 10
hidden_size = 20
output_size = 2
model = SimpleNN(input_size, hidden_size, output_size)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
train_model(model, dataloader, criterion, optimizer)
if __name__ == "__main__":
main()
在HarmonyOS Next中,2in1设备上HdsNavigation组件的titleBar默认会侵入WindowDecor区域。这是系统为适配折叠屏或平板等大屏设备的默认UI行为,旨在优化屏幕空间利用率。
在HarmonyOS Next的2in1设备上,HdsNavigation的titleBar侵入WindowDecor区域,通常是由于设备形态(如平板模式、桌面模式)切换或窗口管理策略差异导致的。您已正确设置了win.setWindowLayoutFullScreen(false)来退出全屏,但问题可能出在导航栏对系统装饰区域(SystemBar)的适配逻辑上。
针对此问题,您可以尝试以下方案:
-
显式设置窗口系统栏可见性:在您的EntryAbility的
onWindowStageCreate生命周期中,在设置非全屏布局后,立即显式地设置系统栏的可见性。这可以确保系统装饰区域被正确保留。import { window } from '@kit.ArkUI'; onWindowStageCreate(windowStage: window.WindowStage) { // ... 其他代码 ... let win = windowStage.getMainWindow(); // 1. 先设置窗口为非全屏布局 win.setWindowLayoutFullScreen(false); // 2. 关键步骤:显式设置系统栏为可见状态 win.setWindowSystemBarEnable(['status', 'navigation']); // ... 其他代码,例如加载页面 ... }setWindowSystemBarEnable(['status', 'navigation'])会明确告知系统,状态栏和导航栏需要被保留,从而为它们预留出空间。这可以防止HdsNavigation等组件侵入该区域。 -
检查并适配窗口安全区域:确保您的UI布局考虑了系统安全区域(Safe Area)。您可以使用
getWindowAvoidAreaAPI获取需要避让的区域(包括系统栏区域),并在布局时进行相应偏移。import { window } from '@kit.ArkUI'; import { BusinessError } from '@kit.BasicServicesKit'; let win = windowStage.getMainWindow(); try { let avoidArea = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); // avoidArea 是一个 Rect 对象,包含top, bottom, left, right四个属性 // 您可以根据这些值来调整HdsNavigation或页面内容的布局位置,例如设置paddingTop。 } catch (error) { let err: BusinessError = error as BusinessError; console.error(`Failed to get avoid area. Code: ${err.code}, message: ${err.message}`); }在UI组件(例如
Column)的样式中,可以使用paddingTop: avoidArea.top来避开顶部的状态栏区域。 -
针对2in1设备形态进行条件判断:2in1设备在不同模式(如平板、笔记本)下,系统栏的行为可能不同。您可以通过
display.getDefaultDisplay()和display.get相关接口获取当前设备的显示信息,并据此调整UI策略。
问题根源分析:在2in1设备上,当应用窗口未设置为全屏时,系统期望应用内容自动避让系统装饰区。HdsNavigation组件可能在某些设备形态下,其内部计算布局的逻辑未能准确获取到最新的系统栏避让区域,导致其titleBar绘制在了预留区域之上。上述方案1通过显式启用系统栏,是最直接有效的解决方式,它强制系统重新计算并应用正确的布局边界。
请优先尝试方案1。如果问题依旧存在,请结合方案2,在获取安全区域后,动态调整包含HdsNavigation的容器布局的padding或margin。


