HarmonyOS 鸿蒙Next中HdsTabs 底部强制留白,怎么去掉?

HarmonyOS 鸿蒙Next中HdsTabs 底部强制留白,怎么去掉? 使用 HdsTabs 组件作为底部 Tab 栏,无论是设置 barOverlap = true 还是 false,底部始终存在一段白色留白区域。

img

img


更多关于HarmonyOS 鸿蒙Next中HdsTabs 底部强制留白,怎么去掉?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

12 回复

这个问题大概率不是 barOverlap 的问题,而是:

HdsTabs 默认会处理底部安全区(SafeArea)

所以即使你:

.barOverlap(true)

底部仍然会预留一块导航指示器区域(小白条区域)。

你截图里那块白色区域,本质上就是:

底部 NavigationIndicator 的安全区占位

尤其:

  • HarmonyOS 6
  • 全面屏设备
  • 手势导航模式

会特别明显。

你现在这个布局:

Column() {
  this.HdsTabComponent()
}
.layoutWeight(1)
.width('100%')
.height('100%')

其实已经让:

HdsTabs + SafeArea

共同撑满了页面。

而 HdsTabs 内部又自动避让底部系统区域,

于是就出现:

TabBar下面还有一截空白

——

解决方案通常有 3 种。

方案1(最推荐)

直接让页面扩展到底部安全区:

Column() {
  this.HdsTabComponent()
}
.width('100%')
.height('100%')
.expandSafeArea(
  [SafeAreaType.SYSTEM],
  [SafeAreaEdge.BOTTOM]
)

或者直接:

HdsTabs() {
}
.expandSafeArea(
  [SafeAreaType.SYSTEM],
  [SafeAreaEdge.BOTTOM]
)

很多情况下这就能消掉底部白边。

——

方案2(HarmonyOS 6 更有效)

关闭 NavigationIndicator 避让。

例如:

windowClass.setWindowLayoutFullScreen(true)

或者:

setSpecificSystemBarEnabled('navigationIndicator', false)

这样系统底部安全区就没了。

但这个属于:

真正沉浸式

一般:

  • 视频
  • 阅读器
  • 游戏

才建议这样干。

普通 App 不太建议。

——

方案3(很多人忽略)

别同时:

.layoutWeight(1)
.height('100%')

你这里:

Column()
  .layoutWeight(1)
  .height('100%')

实际上容易导致:

父布局 + SafeArea 重复计算

建议改成:

Column() {
  this.HdsTabComponent()
}
.width('100%')
.height('100%')

或者:

.layoutWeight(1)
.width('100%')

二选一。

不要同时写。

很多 HdsTabs 底部空白,

其实就是:

layoutWeight + SafeArea

一起作用导致的。

——

另外你代码里还有一个点:

.barHeight(
  new BreakpointType<Length>({
    lg: '100%',
    xl: 0
  })
)

这里:

lg: '100%'

非常危险。

因为:

竖向 Tabs 模式下
barHeight = 100%

有可能会影响整体布局测量。

建议:

.barWidth(...)

和:

.barHeight(...)

分开处理。

——

目前 HarmonyOS 6 的 HdsTabs:

对 SafeArea 的内部处理比较“重”

很多开发者都遇到:

  • 底部白边
  • expandSafeArea 不生效
  • overlap 无效
  • 沉浸式异常

尤其 API23/24 更明显。

更多关于HarmonyOS 鸿蒙Next中HdsTabs 底部强制留白,怎么去掉?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


非常感谢,我之前踩过安全区的坑特意用了应用全屏的方案。结果适配HdsTabs的时候,上下都多了避让。我还想着我走的应用全屏方案它哪来的背景颜色。。。调试发现hds自身是全屏的但是给它加padding竟然会导致这个问题。。。

HdsTabs 底部那段白色区域大概率和系统安全区/手势导航区域有关,不一定是 barOverlap 本身无效。barOverlap 控制的是页签与内容的覆盖关系,但 HDS 容器仍可能为底部系统区域做避让。

建议按这几项查:

  1. 外层如果已经是 HdsNavigation,不要再用普通 Column/Navigation 额外包一层制造二次安全区。

  2. 检查 HdsNavigation 和 HdsTabs 是否都在处理 bottom safe area,重复避让会放大留白。

  3. 需要沉浸到底部时,可在根 HdsNavigation 侧统一处理 ignoreLayoutSafeArea,并确认内容本身 clip 到安全区域。

  4. 给底部区域临时加背景色定位,区分是 HdsTabs 自身 padding、父容器 padding,还是系统导航条安全区。

  5. 如果使用 barFloatingStyle/barBottomMargin,也要确认 margin 不是留白来源。

简单说,先把“只有一个 HdsNavigation 根容器 + 一个 HdsTabs”的最小 demo 跑通,再把业务布局逐层加回去,通常能找到是哪一层重复加了底部避让。

.bindToScrollable([this.scrollerHome, this.scrollerAR, this.scrollerMe])
      .hideBackButton(true)
      .titleMode(HdsNavigationTitleMode.MINI)
      .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])

可以参考一下,我的正常

是不是嵌套有问题。既然用hdstabs了,Navigation可以选择HdsNavigation。
另外包裹在HdsNavigation内的所有控件以及后层级HdsNavDestination的页面在屏幕占比空间,是受根HdsNavigation占比影响的。
下面示例,怎么设置都没出现大片空白。

import {
  DividerMode,
  hdsMaterial,
  HdsNavigation,
  HdsNavigationTitleMode,
  HdsTabs,
  HdsTabsController,
  ScrollEffectType
} from '@kit.UIDesignKit';
import { SymbolGlyphModifier } from '@kit.ArkUI';


@Entry
@Component
struct Index {
  private scrollerForScroll: Scroller = new Scroller();
  private controller: HdsTabsController = new HdsTabsController();
  @State customMaterialLevel: hdsMaterial.MaterialLevel = hdsMaterial.MaterialLevel.EXQUISITE;
  @State isRefreshing: boolean = false;
  @State contacts: string[] = []

  aboutToAppear(): void {
    for (let index = 0; index < 20; index++) {
      this.contacts.push('ListItem  '+index);
    }
    let materialTypes: Array<hdsMaterial.MaterialType> = hdsMaterial.getSystemMaterialTypes();
    if (materialTypes.indexOf(hdsMaterial.MaterialType.IMMERSIVE) < 0) {
      this.customMaterialLevel = hdsMaterial.MaterialLevel.SMOOTH; // 当前设备不支持IMMERSIVE材质类型,则使用SMOOTH效果
    }
  }

  build() {
    HdsNavigation() {
      HdsTabs({ controller: this.controller }) {
        ForEach(MENU_CONFIG, (item: MenuItem) => {
          TabContent() {
            Stack() {
              Refresh({ refreshing: this.isRefreshing }) {
                Scroll(this.scrollerForScroll) {
                  List() {
                    ForEach(this.contacts, (item: string) => {
                      ListItem() {
                        Row() {
                          Text(item).fontSize(20)
                            .height(80)
                        }
                        .width('100%')
                        .justifyContent(FlexAlign.Start)
                      }
                    }, (item: string) => JSON.stringify(item))
                  }
                  .width('100%')
                }
                .clipContent(ContentClipMode.SAFE_AREA)
                .height('100%')
              }.onRefreshing(() => {
                this.isRefreshing = true;
                // 模拟刷新数据
                setTimeout(() => {
                  this.isRefreshing = false;
                }, 3000);
              })

            }
          }
          .backgroundColor('#666666')
          .tabBar(new BottomTabBarStyle({
            normal: item.symbolGlyph, selected: item.symbolGlyph1
          }, item.label))
        })
      }
      .barOverlap(true)
      .vertical(false)
      .barPosition(BarPosition.End)
      .divider({ mode: DividerMode.FOLLOW_SCROLL })
      .barFloatingStyle({
        barBottomMargin: 28,
        systemMaterialEffect: {
          materialType: hdsMaterial.MaterialType.ADAPTIVE,
          materialLevel: this.customMaterialLevel // 底部悬浮页签自定义沉浸光感材质效果
        }
      })
    }
    .mode(NavigationMode.Stack)
    .titleBar({
      content: {
        title: {
          mainTitle: '首页',
        }
      },
      style: {
        scrollEffectOpts: {
          enableScrollEffect: false,
          scrollEffectType: ScrollEffectType.GRADIENT_BLUR,
        },
        systemMaterialEffect: {
          materialType: hdsMaterial.MaterialType.ADAPTIVE,
          materialLevel: this.customMaterialLevel // 标题栏按钮自定义沉浸光感材质效果
        },
      },
      avoidLayoutSafeArea: false,
      enableComponentSafeArea: false
    })
    .hideTitleBar(true)
    .hideBackButton(true)
    .bindToScrollable([this.scrollerForScroll])
    .titleMode(HdsNavigationTitleMode.MINI)
    .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])
  }
}

interface MenuItem {
  symbolGlyph: SymbolGlyphModifier,
  symbolGlyph1: SymbolGlyphModifier,
  label: string,
  defaultBgColor: ResourceColor,
  hoverBgColor: ResourceColor,
  pressBgColor: ResourceColor,
};

const MENU_CONFIG: MenuItem[] = [
  {
    symbolGlyph: new SymbolGlyphModifier($r('sys.symbol.alarm_fill_1')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_bottom_tab_icon_off'),
        $r('sys.color.ohos_id_color_bottom_tab_icon_auxcolor_off02')]),
    symbolGlyph1: new SymbolGlyphModifier($r('sys.symbol.alarm_fill_1')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_activated'), $r('sys.color.ohos_id_color_primary_contrary')]),
    label: '首页',
    defaultBgColor: Color.Transparent,
    hoverBgColor: $r('sys.color.ohos_id_color_hover'),
    pressBgColor: $r('sys.color.ohos_id_color_click_effect')
  },
  {
    symbolGlyph: new SymbolGlyphModifier($r('sys.symbol.worldclock_fill_2')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_bottom_tab_icon_off'),
        $r('sys.color.ohos_id_color_bottom_tab_icon_auxcolor_off02')]),
    symbolGlyph1: new SymbolGlyphModifier($r('sys.symbol.worldclock_fill_2')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_activated'), $r('sys.color.ohos_id_color_primary_contrary')]),
    label: '其他',
    defaultBgColor: Color.Transparent,
    hoverBgColor: $r('sys.color.ohos_id_color_hover'),
    pressBgColor: $r('sys.color.ohos_id_color_click_effect')
  },
  {
    symbolGlyph: new SymbolGlyphModifier($r('sys.symbol.stopwatch_2')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_bottom_tab_icon_off'),
        $r('sys.color.ohos_id_color_bottom_tab_icon_auxcolor_off02')]),
    symbolGlyph1: new SymbolGlyphModifier($r('sys.symbol.stopwatch_2')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_activated'), $r('sys.color.ohos_id_color_primary_contrary')]),
    label: '秒表',
    defaultBgColor: Color.Transparent,
    hoverBgColor: $r('sys.color.ohos_id_color_hover'),
    pressBgColor: $r('sys.color.ohos_id_color_click_effect')
  },
  {
    symbolGlyph: new SymbolGlyphModifier($r('sys.symbol.stopwatch_2')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_bottom_tab_icon_off'),
        $r('sys.color.ohos_id_color_bottom_tab_icon_auxcolor_off02')]),
    symbolGlyph1: new SymbolGlyphModifier($r('sys.symbol.stopwatch_2')).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
      .fontColor([$r('sys.color.ohos_id_color_activated'), $r('sys.color.ohos_id_color_primary_contrary')]),
    label: '秒表',
    defaultBgColor: Color.Transparent,
    hoverBgColor: $r('sys.color.ohos_id_color_hover'),
    pressBgColor: $r('sys.color.ohos_id_color_click_effect')
  }

];

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

开发者你好,可以分别排查下问题:

1、去掉.barHeight代码,测试一下;

2、增加高度和宽度为100%,再测试一下。

cke_159.png

在 Index.ets 文件中,我给 Navigation 组件添加了以下配置:.hideTitleBar(true)

.hideBackButton(true)就好了

很喜欢HarmonyOS的卡片式设计,信息一目了然,操作也更便捷。

你好,

在鸿蒙Next中,HdsTabs底部留白通常由默认padding或底部安全区补偿导致。配置组件的padding({bottom:0})margin({bottom:0})或通过.height(0)覆盖默认样式即可去除。若为自定义TabBar,检查父容器ListRowpadding

底部白色留白是安全区域适配导致的,HdsTabs 默认会避让底部手势指示条区域。解决方法是在包裹 Tabs 的最外层组件启用底部安全区延伸:

Tabs({ barPosition: BarPosition.End }) {
  TabContent() { ... }
  .tabBar('首页')
  ...
}
.height('100%')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
.barHeight(56) // 按实际设计高度设置

若外层有 ColumnNavigation,则在其 build 里加上 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM]),并确保布局高度撑满。barOverlap 与此无关,可不设置。

回到顶部