HarmonyOS鸿蒙Next中HdsTabs组件的控制器可以控制页签栏的显示和隐藏,这个显示和隐藏的动效时间可以设置吗?

HarmonyOS鸿蒙Next中HdsTabs组件的控制器可以控制页签栏的显示和隐藏,这个显示和隐藏的动效时间可以设置吗? 【问题描述】:HdsTabs组件的控制器可以控制页签栏的显示和隐藏,这个显示和隐藏的动效时间可以设置吗?

【问题现象】:HdsTabs组件的控制器可以控制页签栏的显示和隐藏,这个显示和隐藏的动效时间可以设置吗?

在HdsTabs组件中有一个page页,在page页里跳转page2页,跳转时调用接口applyHideAnimation隐藏,page2返回page时调用applyShowAnimation显示,感觉隐藏和显示时的动画慢,页面已经切换完了,动画还没走完

相关链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ui-design-hdstabs#applyhideanimation

【版本信息】:API23

【复现代码】:不涉及

【尝试解决方案】:暂无


更多关于HarmonyOS鸿蒙Next中HdsTabs组件的控制器可以控制页签栏的显示和隐藏,这个显示和隐藏的动效时间可以设置吗?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

17 回复

开发者您好,本地测试了两个demo,开发者可以参考下,本地测试动画效果不是很慢:

1、用onVisibleAreaChange,页面显示一半就触发隐藏或显示tabbar动效

参考:

// 从6.0.2(22)版本开始,无需手动导入HdsTabsAttribute。具体请参考HdsTabs的导入模块说明。
import { hdsMaterial } from '@hms.hds.hdsMaterial'
import { HdsTabs, HdsTabsAttribute, HdsTabsController } from '@kit.UIDesignKit';

@Entry
@Component
struct Index {
  // 初始化HdsTabs控制器。
  private controller: HdsTabsController = new HdsTabsController();

  @Builder
  tabContentBuilder(color: Color) {
    List() {
      ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number) => {
        ListItem() {
          Column() {
            Row() {
            }.height(200)
            .width('100%')

            Row() {
            }.width('100%')
            .height(50)
            .background(color)
          }
        }
      })
    }
  }

  @Builder
  miniBarBuilder() {
    Row() {
      Column() {
        Image($r('app.media.startIcon'))
          .width(40)
          .height(40)
          .borderRadius(40)
      }.width(48).height(48).justifyContent(FlexAlign.Center)

      Text('Hello')

      Column() {
        Image($r('sys.media.ohos_ic_public_pause'))
          .width(40)
          .height(40)
          .borderRadius(40)
      }.width(48).height(48).justifyContent(FlexAlign.Center)
    }
  }

  build() {
    Column() {
      HdsTabs({ controller: this.controller }) {
        TabContent() {
          this.tabContentBuilder(Color.Green)
        }
        .onVisibleAreaChange([0.5, 1.0], (isExpanding: boolean, currentRatio: number) => {
          if (isExpanding && currentRatio >= 0.5 && currentRatio <= 1) {
            this.controller.applyShowAnimation(0);
          }
          if (!isExpanding && currentRatio <= 0.5) {
            this.controller.applyHideAnimation(0);
          }
        })
        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_ic_public_clock'), 'Green'))

        TabContent() {
          this.tabContentBuilder(Color.Blue)
        }
        .tabBar(new BottomTabBarStyle($r('sys.media.wifi_router_fill'), 'Blue'))

        TabContent() {
          this.tabContentBuilder(Color.Yellow)
        }
        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_ic_public_clock'), 'Yellow'))
      }
      // 设置barOverlap为true,vertical为false,barPosition为BarPosition.End
      .barOverlap(true)
      .barPosition(BarPosition.End)
      .vertical(false)
      // 设置页签栏悬浮样式。
      .barFloatingStyle({
        barWidth: { smallWidth: 200, mediumWidth: 300, largeWidth: 400 },
        barBottomMargin: 28,
        gradientMask: { maskColor: '#66F1F3F5', maskHeight: 92 },
        systemMaterialEffect: {
          materialType: hdsMaterial.MaterialType.IMMERSIVE,
          materialLevel: hdsMaterial.MaterialLevel.EXQUISITE
        },
        // 设置迷你栏,若不设置,则仅有页签栏。
        miniBar: {
          miniBarBuilder: () => this.miniBarBuilder()
        }
      })
    }
  }
}

2、用onAnimationStart,切换页面开始时触发tabbar显示/隐藏

参考:

// 从6.0.2(22)版本开始,无需手动导入HdsTabsAttribute。具体请参考HdsTabs的导入模块说明。
import { hdsMaterial } from '@hms.hds.hdsMaterial'
import { HdsTabs, HdsTabsAttribute, HdsTabsController } from '@kit.UIDesignKit';

@Entry
@Component
struct Index {
  // 初始化HdsTabs控制器。
  private controller: HdsTabsController = new HdsTabsController();

  @Builder
  tabContentBuilder(color: Color) {
    List() {
      ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number) => {
        ListItem() {
          Column() {
            Row() {
            }.height(200)
            .width('100%')

            Row() {
            }.width('100%')
            .height(50)
            .background(color)
          }
        }
      })
    }
  }

  @Builder
  miniBarBuilder() {
    Row() {
      Column() {
        Image($r('app.media.startIcon'))
          .width(40)
          .height(40)
          .borderRadius(40)
      }.width(48).height(48).justifyContent(FlexAlign.Center)

      Text('Hello')

      Column() {
        Image($r('sys.media.ohos_ic_public_pause'))
          .width(40)
          .height(40)
          .borderRadius(40)
      }.width(48).height(48).justifyContent(FlexAlign.Center)
    }
  }

  build() {
    Column() {
      HdsTabs({ controller: this.controller }) {
        TabContent() {
          this.tabContentBuilder(Color.Green)
        }
        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_ic_public_clock'), 'Green'))

        TabContent() {
          this.tabContentBuilder(Color.Blue)
        }
        .tabBar(new BottomTabBarStyle($r('sys.media.wifi_router_fill'), 'Blue'))

        TabContent() {
          this.tabContentBuilder(Color.Yellow)
        }
        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_ic_public_clock'), 'Yellow'))
      }
      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent)=>{
        if (index === 1) {
          this.controller.applyShowAnimation(0);
        }
        else {
          this.controller.applyHideAnimation(0);
        }
      })
      // 设置barOverlap为true,vertical为false,barPosition为BarPosition.End
      .barOverlap(true)
      .barPosition(BarPosition.End)
      .vertical(false)
      // 设置页签栏悬浮样式。
      .barFloatingStyle({
        barWidth: { smallWidth: 200, mediumWidth: 300, largeWidth: 400 },
        barBottomMargin: 28,
        gradientMask: { maskColor: '#66F1F3F5', maskHeight: 92 },
        systemMaterialEffect: {
          materialType: hdsMaterial.MaterialType.IMMERSIVE,
          materialLevel: hdsMaterial.MaterialLevel.EXQUISITE
        },
        // 设置迷你栏,若不设置,则仅有页签栏。
        miniBar: {
          miniBarBuilder: () => this.miniBarBuilder()
        }
      })
    }
  }
}

开发者如果感觉还是慢,请提供下您本地测试的demo,方便我们这边进一步分析下问题

更多关于HarmonyOS鸿蒙Next中HdsTabs组件的控制器可以控制页签栏的显示和隐藏,这个显示和隐藏的动效时间可以设置吗?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


开发者您好,可以使用HdsNavigation嵌套HdsTabs的形式:

import { HdsTabsController, HdsTabs, hdsMaterial, HdsNavigation, ScrollEffectType,
  HdsNavDestination,
  HdsNavDestinationTitleMode,
  HdsAnimationMode} from "@kit.UIDesignKit";

export const mainTabController = new HdsTabsController();

@Entry
@Component
struct Index {
  private navPathStack = new NavPathStack();

  @Builder
  pageMap(name: string) {
    if (name == 'DemoPage2') {
      DemoPage2();
    }
  }


  build() {
    Column() {
      HdsNavigation(this.navPathStack) {
        HdsTabs({ controller: mainTabController }) {
          TabContent() {
            Button("点击页面跳转")
              .onClick(() => {
                mainTabController.applyHideAnimation(HdsAnimationMode.SCROLL_ANIMATION);
                this.navPathStack.pushPathByName("DemoPage2", null);
              })
          }
          .tabBar("DEMO")
        }
        .vertical(false)
        .barOverlap(true)
        .scrollable(false)
        .animationDuration(0)
        .barPosition(BarPosition.End)
        .barFloatingStyle({
          barBottomMargin: 30,
          gradientMask: { maskColor: "#66F1F3F5", maskHeight: 92 },
          systemMaterialEffect: {
            materialType: hdsMaterial.MaterialType.ADAPTIVE,
            materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
          }
        })
      }
      .navDestination(this.pageMap)
      .hideToolBar(true)
      .hideBackButton(true)
      .backgroundColor($r("sys.color.background_secondary"))
      .titleBar({
        content: {
          title: { mainTitle: "首页" },
        },
        style: {
          scrollEffectOpts: {
            enableScrollEffect: false,
            scrollEffectType: ScrollEffectType.GRADIENT_BLUR
          },
          systemMaterialEffect: {
            materialType: hdsMaterial.MaterialType.ADAPTIVE,
            materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
          }
        },
        avoidLayoutSafeArea: true,
        enableComponentSafeArea: true
      })

    }
  }
}


@ComponentV2
struct DemoPage2 {
  private navPathStack?: NavPathStack;

  build() {
    HdsNavDestination() {
    }
    .hideToolBar(true)
    .size({ width: "100%", height: "100%" })
    .backgroundColor($r("sys.color.background_secondary"))
    .titleMode(HdsNavDestinationTitleMode.MINI)
    .titleBar({
      content: {
        title: { mainTitle: "跳转页面" }
      },
      style: {
        scrollEffectOpts: {
          enableScrollEffect: false,
          scrollEffectType: ScrollEffectType.GRADIENT_BLUR
        },
        systemMaterialEffect: {
          materialType: hdsMaterial.MaterialType.ADAPTIVE,
          materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
        }
      },
      avoidLayoutSafeArea: true
    })
    .onReady((context) => {
      this.navPathStack = context.pathStack;
    })
    .onBackPressed(() => {
      // 显示主Tab
      mainTabController.applyShowAnimation(HdsAnimationMode.SCROLL_ANIMATION);
      return false;
    })
  }
}

老师,我的问题是这样的,在这个HdsTabs组件里有一个pgae页(index加载的就是这个页面),在page页跳转到page2页时隐藏,page2跳转page时显示。demo和录屏已发

老师,您提供的demo开启深色模式和关闭深色模式,会导致UI布局的改变

HdsTabs 控制器 applyHideAnimation() / applyShowAnimation() 的动效时长可以通过 animationDuration 属性控制,这是控制页签栏自身动画的属性。

通过控制器

// 获取控制器
private tabsController: TabsController = new TabsController()

// 在需要隐藏页签栏时
this.tabsController.animationDuration(100)  // 单位:毫秒
this.tabsController.applyHideAnimation()

// 在需要显示页签栏时
this.tabsController.animationDuration(100)
this.tabsController.applyShowAnimation()

参考文档:

cke_740.png

你的问题主要是 TabContent 切换动画太慢,把 Tabs(animationDuration: 100) 调小就能解决。页签栏的 applyHideAnimation() 如果你不需要隐藏显示效果,animationDuration 设为 0 即可跳过它的动画。

也可以直接进行属性绑定,

HdsTabs({
  controller: this.tabsController,
  barHeight: this.tabBarVisible ? 56 : 0,  // 高度动画
})
.animation({
  duration: 100,    // 页签栏高度变化的动画时长,单位ms
  curve: Curve.EaseOut,
})

是的,HdsTabs组件的显示和隐藏动画时间通常是可以设置的。

这个功能一般是通过为HdsTabs组件或其控制器(Controller)设置一个 持续时间(Duration) 属性来实现的。这个属性决定了动画从开始到结束所需的毫秒数。

您可以尝试在代码中查找与HdsTabs相关的配置项,特别是以下几种可能性:

  1. 直接设置组件的duration属性

许多UI组件库允许在组件实例化时直接传入一个duration参数。您可以查看HdsTabs的构造函数或配置选项,看是否有类似下面的设置方式:

    HdsTabs(
      controller: _tabController,
      duration: Duration(milliseconds: 300), // 设置动画持续时间为300毫秒
      // 其他属性...
    )
  1. 通过控制器(Controller)设置

您提到了使用“控制器”来控制页签栏的显示和隐藏。有些组件会将动画相关的配置放在控制器中。您可以检查控制器的构造函数或相关方法,看是否可以传入duration参数。

  1. 查找组件的动画配置参数

仔细查阅HdsTabs组件的官方文档或API参考,寻找与“动画”、“动效”、“持续时间”等关键词相关的参数。不同的组件库命名习惯不同,可能的参数名还包括 animationDuration 、 tabAnimationDuration 等。

如果以上方法都无法找到确切的设置项,建议您查阅该UI库的官方文档或向其技术支持咨询,以获取最准确的配置信息。

针对你提到的 HdsTabs 组件控制器控制页签栏(TabBar)显示和隐藏时,动画时长无法调整的问题,在当前的 API 版本(API 23 / 6.0.1)中,无法直接通过属性设置来修改这个特定的显示/隐藏动效时间。

虽然 HdsTabs 提供了 animationDuration 属性,但它仅控制**页签内容切换(TabContent Change)的动画时长,而不控制页签栏整体显隐(Bar Show/Hide)**的动画时长。

以下是详细的技术分析和建议:

1. 为什么无法设置?(属性作用域分析)

根据华为开发者文档,HdsTabs 相关的动画属性如下表所示:

属性名 作用对象 控制内容 你的场景是否适用
animationDuration TabContent (内容区) 控制点击页签或调用 changeIndex 切换页面时的滑动动画时长。 不适用。这是页面切换,不是栏的显隐。
barBackgroundBlurStyle TabBar (页签栏) 设置背景模糊样式(如 BlurStyle),通常用于模糊效果的定义,不包含显隐时间。 不适用
barOverlap TabBar (页签栏) 设置页签栏是否叠加在内容之上并开启模糊,不涉及动画时长。 不适用

结论: 文档中没有提供类似 barAnimationDurationhideAnimationDuration 的属性来控制页签栏自身的显示和隐藏速度。

2. 问题根源分析

你提到的现象——“页面已经切换完了,动画还没走完”,通常是因为:

  1. 控制器逻辑: 当你通过控制器(如自定义逻辑)控制 TabBar 的显隐时,系统使用的是默认的“标准动效曲线”和“标准时长”。
  2. 动效与逻辑解耦: 在 API 23 中,UI 组件的显隐动效时长通常是硬编码在系统动效库中的,为了保持系统级的视觉一致性,开发者无法直接覆盖这一底层时间参数。

3. 建议解决方案

由于无法直接修改控制器的动效时间,建议通过以下两种方式优化体验:

方案 A:调整业务逻辑的时序(推荐)

不要等待 TabBar 动画结束再进行后续操作。

  • 做法: 在触发页面切换(逻辑完成)后,立即执行后续业务,不要去监听 TabBar 动画的结束回调(如果有的话)。
  • 原理: 将“页面逻辑切换”与“UI 动画播放”解耦。即使动画还在播放,只要逻辑上页面已经准备好,用户就可以进行交互,视觉上的滞后感会降低。

方案 B:降级使用基础 Tabs 组件

如果 HdsTabs 的固定动效严重影响了你的应用体验,且必须自定义速度,可以考虑回退到原生的 ArkUI Tabs 组件。

  • 做法: 使用标准的 Tabs + Column/Stack 布局手动构建页签栏。
  • 优势: 手动构建的 UI 元素(如 Column)可以通过 animateTo 或属性动画完全自定义显示和隐藏的时间(例如设置为 100ms)。
  • 代价: 需要自己实现 HdsTabs 提供的高级特性(如分割线、半屏居中、特定的模糊样式等)。

4. 补充信息

你提供的链接 #applyhideanimation 在官方文档中通常是关于“应用隐藏动画”的章节,这与 HdsTabs 组件内部的 UI 动画是两个不同的概念,请勿混淆。

总结: 目前无法通过配置修改该动效时间。建议优先采用 方案 A,在代码逻辑上忽略该动画的耗时,以解决“页面切换慢”的感知问题。

刚刚测试过,目前HdsTabs的设置里只有改变动效模式,没有改动画时长的,改为

| CLICK_ANIMATION | 1 | 点击动效 |

会感觉快一点,但整个光感效果是持续的,和设备性能也有一定关系吧:

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

@Entry
@Component
export struct Index {
  private scrollerForScroll: Scroller = new Scroller();
  private controller: HdsTabsController = new HdsTabsController();

  aboutToAppear() {
    
    this.controller.applyHideAnimation(HdsAnimationMode.CLICK_ANIMATION);
    this.controller.applyShowAnimation(HdsAnimationMode.CLICK_ANIMATION );
  }

  private menus: HdsNavigationMenuContentOptions = {
    value: [{
      content: {
        label: 'menu1',
        icon: $r('sys.symbol.square_and_pencil'),
      }
    }, {
      content: {
        label: 'menu2',
        icon: $r('sys.symbol.star')
      },
    },{
      content: {
        label: 'menu3',
        icon: $r('sys.symbol.more')
      },
    }
    ],
  };

  build() {
    HdsNavigation() {
      HdsTabs({ controller: this.controller }) {
        ForEach(MENU_CONFIG, (item: MenuItem) => {
          TabContent() {
            Stack() {
              Scroll(this.scrollerForScroll) {
                Column() {
                  Image($r("app.media.scenery01")).width('100%') // scenery为自定义资源,开发者需替换本地资源
                }
              }
              .clipContent(ContentClipMode.SAFE_AREA)
              .height('100%')
            }
          }
          .tabBar(new BottomTabBarStyle({
            normal: item.symbolGlyph, selected: item.symbolGlyph1
          }, item.label))
        })
      }
      .barOverlap(true)
      .vertical(false)
      .barPosition(BarPosition.End)
      .barFloatingStyle({
        barBottomMargin: 28,
        systemMaterialEffect:  {
          materialType: hdsMaterial.MaterialType.ADAPTIVE,
          materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE // 底部悬浮页签沉浸光感效果跟随系统策略自适应
        }
      })
    }
    .mode(NavigationMode.Stack)
    .titleBar({
      content: {
        title: {
          mainTitle: 'MainTitle',
        },
        menu: this.menus,
      },
      style: {
        scrollEffectOpts: {
          enableScrollEffect: false,
          scrollEffectType: ScrollEffectType.GRADIENT_BLUR,
        },
        systemMaterialEffect: {
          materialType: hdsMaterial.MaterialType.ADAPTIVE,
          materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE // 标题栏按钮沉浸光感效果跟随系统策略自适应
        },
      },
      avoidLayoutSafeArea: false,
      enableComponentSafeArea: false
    })
    .bindToScrollable([this.scrollerForScroll])
    .hideBackButton(false)
    .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')
  }
];

HdsAnimationMode

PhonePC/2in1TabletTV

显示隐藏动效模式。

模型约束: 此接口仅可在Stage模型下使用。

系统能力: SystemCapability.UIDesign.HDSComponent.Core

设备行为差异: 该接口在TV无效果,在其他设备类型中可正常调用。

起始版本: 6.1.0(23)

名称 说明
SCROLL_ANIMATION 0 滚动动效。
CLICK_ANIMATION 1 点击动效。

HdsBarStyle

PhonePC/2in1TabletTV

页签栏和迷你栏样式类型枚举。

模型约束: 此接口仅可在Stage模型下使用。

系统能力: SystemCapability.UIDesign.HDSComponent.Core

设备行为差异: 该接口在TV无效果,在其他设备类型中可正常调用。

起始版本: 6.1.0(23)

展开

名称 说明
COLLAPSE 0 折叠样式。
EXPAND 1 展开样式。

img

您遇到的问题是"页面导航切换时动画太慢",这里需要区分两个不同的动画:

  1. TabContent切换动画 - 点击TabBar切换页面内容的动画
  2. TabBar显示/隐藏动画 - 调用applyHideAnimation()/applyShowAnimation()时的动画

解决方案

方案一:控制TabContent切换动画时长

Tabs({ animationDuration: 100 }) // 单位:毫秒,设置为100ms可加快切换速度

这个属性控制的是TabContent之间的切换动画时长,默认300ms。

方案二:控制TabBar显示/隐藏动画时长

// 通过控制器设置
this.tabsController.animationDuration(100) // 先设置时长
this.tabsController.applyHideAnimation()   // 再执行隐藏动画

this.tabsController.animationDuration(100)
this.tabsController.applyShowAnimation()   // 执行显示动画

方案三:通过属性绑定实现平滑过渡

HdsTabs({
  controller: this.tabsController,
  barHeight: this.tabBarVisible ? 56 : 0
})
.animation({
  duration: 100,  // 动画时长
  curve: Curve.EaseOut  // 动画曲线
})

关于 HdsTabs 页签栏显示/隐藏动画时间的设置

目前 HdsTabs 控制器的 setTabBarVisible 或 applyHideAnimation 方法不支持直接设置动画时长参数。

现状分析:

HdsTabs 是 UI Design Kit 的高级组件,它基于基础的 Tabs 组件进行了封装

基础 Tabs 组件的 animationDuration 属性只能控制 TabContent 内容切换的动画时长,不能控制页签栏(TabBar)显示/隐藏的动画时长

HdsTabsController 的方法其动画时长是固定的,无法通过参数自定义

一、解决方案建议:

1、自定义动画时长控制(推荐方案)

hideTabBar() / showTabBar() - 使用 150ms 自定义动画

2、通过 animateTo + 控制 barHeight 和 opacity 实现

快速切换(无动画)

3、quickHideTabBar() / quickShowTabBar() - 瞬间切换,无过渡效果

控制器方法(固定动画时长)

hideWithController() / showWithController() - 使用系统默认动画时长

4、4个完整页签

首页、发现、消息、我的

每个页签有不同的背景色便于区分

二、测试按钮:

隐藏(150ms) / 显示(150ms) - 自定义动画时长的切换

快速隐藏 - 无动画瞬间隐藏

快速显示 - 无动画瞬间显示

控制器隐藏 - 使用控制器的固定动画

控制器显示 - 使用控制器的固定动画

💡 关键代码要点:

// 1. 状态管理
@State tabBarHeight: number = 56
@State tabBarOpacity: number = 1
@State isTabBarVisible: boolean = true

// 2. 自定义动画(可设置 duration)
this.getUIContext().animateTo({
  duration: 150,  // 这里可以自定义动画时长
  curve: Curve.EaseOut
}, () => {
  this.tabBarHeight = 0
  this.tabBarOpacity = 0
})

// 3. 应用到 HdsTabs
HdsTabs({...})
  .barHeight(this.tabBarHeight)  // 绑定高度
  .opacity(this.tabBarOpacity)    // 绑定透明度

完整示例代码:

import { HdsTabs, HdsTabsController } from '@kit.UIDesignKit'
import router from '@ohos.router'

/**
 * @author J.query
 * @date 2026/4/15 19:04
 * @email j-query@foxmail.com
 * Description: HdsTabs 页签栏显示/隐藏动画示例
 */
@Entry
@Component
struct MyPage {
  @State tabBarHeight: number = 56 // 正常高度
  @State tabBarOpacity: number = 1
  @State currentIndex: number = 0
  @State isTabBarVisible: boolean = true
  private controller: HdsTabsController = new HdsTabsController()

  // 隐藏页签栏 - 自定义动画时长
  hideTabBar() {
    if (!this.isTabBarVisible) {
      return
    }
    this.getUIContext().animateTo({
      duration: 150,  // 自定义动画时长,例如 150ms
      curve: Curve.EaseOut
    }, () => {
      this.tabBarHeight = 0
      this.tabBarOpacity = 0
      this.isTabBarVisible = false
    })
  }

  // 显示页签栏 - 自定义动画时长
  showTabBar() {
    if (this.isTabBarVisible) {
      return
    }
    this.getUIContext().animateTo({
      duration: 150,  // 自定义动画时长
      curve: Curve.EaseIn
    }, () => {
      this.tabBarHeight = 56
      this.tabBarOpacity = 1
      this.isTabBarVisible = true
    })
  }

  // 切换页签栏显示/隐藏
  toggleTabBar() {
    if (this.isTabBarVisible) {
      this.hideTabBar()
    } else {
      this.showTabBar()
    }
  }

  // 快速隐藏(无动画)
  quickHideTabBar() {
    this.tabBarHeight = 0
    this.tabBarOpacity = 0
    this.isTabBarVisible = false
  }

  // 快速显示(无动画)
  quickShowTabBar() {
    this.tabBarHeight = 56
    this.tabBarOpacity = 1
    this.isTabBarVisible = true
  }

  // 使用 animateTo 控制隐藏(带动画)
  hideWithController() {
    this.getUIContext().animateTo({
      duration: 300,  // 使用默认动画时长
      curve: Curve.EaseOut
    }, () => {
      this.tabBarHeight = 0
      this.tabBarOpacity = 0
      this.isTabBarVisible = false
    })
  }

  // 使用 animateTo 控制显示(带动画)
  showWithController() {
    this.getUIContext().animateTo({
      duration: 300,  // 使用默认动画时长
      curve: Curve.EaseIn
    }, () => {
      this.tabBarHeight = 56
      this.tabBarOpacity = 1
      this.isTabBarVisible = true
    })
  }

  build() {
    Column() {
      // 控制按钮区域
      Row({ space: 10 }) {
        Button(this.isTabBarVisible ? '隐藏(150ms)' : '显示(150ms)')
          .fontSize(12)
          .height(36)
          .onClick(() => {
            this.toggleTabBar()
          })

        Button('快速隐藏')
          .fontSize(12)
          .height(36)
          .backgroundColor('#FF6B6B')
          .onClick(() => {
            this.quickHideTabBar()
          })

        Button('快速显示')
          .fontSize(12)
          .height(36)
          .backgroundColor('#4ECDC4')
          .onClick(() => {
            this.quickShowTabBar()
          })

        Button('控制器隐藏')
          .fontSize(12)
          .height(36)
          .backgroundColor('#95E1D3')
          .onClick(() => {
            this.hideWithController()
          })

        Button('控制器显示')
          .fontSize(12)
          .height(36)
          .backgroundColor('#F38181')
          .onClick(() => {
            this.showWithController()
          })
      }
      .width('100%')
      .padding({ top: 10, bottom: 10, left: 10, right: 10 })
      .justifyContent(FlexAlign.SpaceEvenly)

      // HdsTabs 组件
      HdsTabs({ controller: this.controller, index: this.currentIndex }) {
        TabContent() {
          Column() {
            Text('首页内容')
              .fontSize(24)
              .fontWeight(FontWeight.Bold)
              .margin({ top: 50 })
            
            Text('当前页签索引: ' + this.currentIndex)
              .fontSize(16)
              .margin({ top: 20 })
              .fontColor('#666666')
            
            Text('页签栏状态: ' + (this.isTabBarVisible ? '显示' : '隐藏'))
              .fontSize(16)
              .margin({ top: 10 })
              .fontColor('#666666')
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#F5F5F5')
          .justifyContent(FlexAlign.Center)
        }
        .tabBar({
          icon: $r('app.media.public_home_normal'),
          text: '首页'
        })

        TabContent() {
          Column() {
            Text('发现内容')
              .fontSize(24)
              .fontWeight(FontWeight.Bold)
              .margin({ top: 50 })
            
            Text('当前页签索引: ' + this.currentIndex)
              .fontSize(16)
              .margin({ top: 20 })
              .fontColor('#666666')
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#E8F5E9')
          .justifyContent(FlexAlign.Center)
        }
        .tabBar({
          icon: $r('app.media.public_ic_search'),
          text: '发现'
        })

        TabContent() {
          Column() {
            Text('消息内容')
              .fontSize(24)
              .fontWeight(FontWeight.Bold)
              .margin({ top: 50 })
            
            Text('当前页签索引: ' + this.currentIndex)
              .fontSize(16)
              .margin({ top: 20 })
              .fontColor('#666666')
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#E3F2FD')
          .justifyContent(FlexAlign.Center)
        }
        .tabBar({
          icon: $r('app.media.public_app_message'),
          text: '消息'
        })

        TabContent() {
          Column() {
            Text('我的内容')
              .fontSize(24)
              .fontWeight(FontWeight.Bold)
              .margin({ top: 50 })
            
            Text('当前页签索引: ' + this.currentIndex)
              .fontSize(16)
              .margin({ top: 20 })
              .fontColor('#666666')
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#FFF3E0')
          .justifyContent(FlexAlign.Center)
        }
        .tabBar({
          icon: $r('app.media.public_app_setting'),
          text: '我的'
        })
      }
      .barHeight(this.tabBarHeight)
      .opacity(this.tabBarOpacity)
      .barPosition(BarPosition.End)
      .vertical(false)
      .onChange((index: number) => {
        this.currentIndex = index
        console.info('页签切换到索引: ' + index)
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}

如果是在页面导航切换时感觉动画慢,如果你想让动画更快,可以修改 duration 值:

100ms - 非常快速

150ms - 快速(当前设置)

200ms - 适中

300ms - 标准速度

现在你可以运行这个页面,点击不同的按钮来体验各种动画效果!

• 使用Transition过渡动画 :利用HarmonyOS提供的Transition组件,可以为单个组件在显示和消失时定义过渡动画效果 。

HdsTabs组件的控制器目前无法设置控制页签栏的显示和隐藏的动效时长,目前官方没有推出设置时长的相关API。

可以的,在API23及对应HarmonyOS版本下,HdsTabs组件支持通过animationDuration属性设置页签栏(TabBar)显示/隐藏以及页面切换的动效时长,具体实现方式如下:

一、核心配置说明

属性作用:animationDuration是HdsTabs组件专门用于配置点击TabBar页签、调用HdsTabsController.changeIndex() 切换TabContent时的动画时长参数,单位为毫秒(ms)。

默认值规则:

  • 若TabBar为BottomTabBarStyle样式,未设置/异常值时默认时长为0ms;
  • 若为其他样式的TabBar,未设置时默认时长为300ms。

设备限制:该属性在TV设备上无效果,Phone/PC/平板等设备可正常生效。

二、代码实现示例

// 1. 导入HdsTabs相关模块
import { HdsTabs, HdsTabsController } from '@ohos/ui-design-kit';

@Component
struct HdsTabsDemo {
  // 2. 创建控制器实例
  private tabsController: HdsTabsController = new HdsTabsController();
  // 3. 自定义动画时长(单位ms,可根据需求调整)
  private customAnimDuration: number = 150;

  build() {
    Column() {
      HdsTabs({
        controller: this.tabsController
      }) {
        // 页签内容配置...
      }
      // 4. 设置自定义动效时长
      .animationDuration(this.customAnimDuration)
      // 其他样式配置...
    }
  }
}

三、补充说明

如果需要快速关闭切换动画,可将animationDuration设置为0ms;若想加快切换速度,可设置小于默认300ms的数值(如100ms/150ms),反之调大数值可放缓动画节奏,能直接解决你提到的“页面已切换但动画未走完”的体验问题。

用过了,这个animationDuration是控制页签之间切换的动画时间,对页面导航没有效果

好吧,

HdsTabs组件控制器的显示/隐藏动效时间可通过设置组件的animationDuration属性进行自定义,默认值固定。该属性接受数值(单位毫秒),修改后生效。无其他动态调整接口。

HdsTabs 控制器的 applyHideAnimation/applyShowAnimation 接口不支持设置显示和隐藏的动效时间,动画时长由系统固定,无法通过参数修改。

回到顶部