前言

本案例展示了状态栏的动态交互效果。通过监听页面滚动事件 onDidScroll,随着页面的上下滚动,实现状态栏颜色的变化。搜索框会在滚动时流畅地展开或收起,并伴有自然的透明度过渡效果。

效果图预览

使用说明

  1. 进入页面开始加载,加载完成后显示整个界面,上下滚动页面即可。

实现思路

  • 初始化和状态设置
    在 aboutToAppear() 方法中,初始化了窗口模型 windowModel。启用沉浸式(设置全屏显示和状态栏为白色),获取状态栏高度存储在 statusBarHeight 变量中,从预定义的数据源 LIST_DATA 加载数据到 dataSource中。

    aboutToAppear(): void {
      // 初始化窗口管理model
      const windowStage: window.WindowStage | undefined = AppStorage.get('windowStage');
      // 没有windowStage将无法执行下列逻辑
      if (!windowStage) {
        logger.error(TAG, 'windowStage init error!');
        return;
      }
      this.windowModel.setWindowStage(windowStage);
      // 设置沉浸模式及状态栏白色
      this.windowModel.setImmersive();
      // 获取顶部状态栏高度
      this.windowModel.getStatusBarHeight((statusBarHeight) => {
        logger.info(TAG, 'statusBarHeight is ' + statusBarHeight);
        this.statusBarHeight = px2vp(statusBarHeight);
      })
      // 组装数据源
      this.dataSource.pushArrayData(LIST_DATA)
    }
    
  • 界面布局构造
    使用Stack控件使状态栏与列表重叠,并为列表添加滚动监听器,以根据滚动位置调整状态栏和导航栏的透明度及展开收起动效。

    Stack({ alignContent: Alignment.Top }) {
      Row() {
        // 动态显示回顶部或位置天气控件
        if (this.isFlow) {
          this.topUpBuilder()
        } else {
          this.locationAndWeatherBuilder()
        }
        this.searchViewBuilder()
        this.toolViewBuilder()
      }
      .height(Constants.NAVIGATION_BAR_HEIGHT + this.statusBarHeight)
        .width(Constants.FULL_PERCENT)
        .padding({
          top: this.statusBarHeight
        })
        .zIndex(Constants.Z_INDEX_THREE)
    
      // TODO: 知识点:父组件的透明度Opacity影响子组件(如父类Opacity为0.5,若子组件为0.5时,子组件实际Opacity = 0.5*0.5),此处Row来改变状态栏的透明度不受影响其它组件透明度
      Row() {
      }
      .backgroundColor($r("app.color.status_bar_animation_white"))
        .opacity(this.navigateBarOpacity)
        .height(Constants.STATUS_BAR_HEIGHT + this.statusBarHeight)
        .width(Constants.FULL_PERCENT)
        .zIndex(Constants.Z_INDEX_TWO)
    
      List({ scroller: this.scroller }) {
        // ...
      }
      // 隐藏滚动条
      .scrollBar(BarState.Off)
        // 渐变蓝色背景色
        .linearGradient({
          colors: [[Constants.LIST_LINEAR_GRADIENT_START_COLOR, Constants.LIST_LINEAR_GRADIENT_START],
            [Constants.LIST_LINEAR_GRADIENT_END_COLOR, Constants.LIST_LINEAR_GRADIENT_END]]
        })
        .height(Constants.FULL_PERCENT)
        .width(Constants.FULL_PERCENT)
    }
    .zIndex(Constants.Z_INDEX_ONE)
      .height(Constants.FULL_PERCENT)
      .width(Constants.FULL_PERCENT)
        // 扩展至所有非安全区域
      .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
    
  • 滚动事件处理
    通过监听页面滚动事件 onDidScroll,根据当前的滚动偏移量 yOffset 调整状态栏和导航栏的透明度。如果滚动超过了设定的阈值,则改变状态栏的颜色和展开收起动画。

    .onDidScroll(() => {
      // TODO: 知识点:通过currentOffset来获取偏移量比较准确。
      const yOffset: number = this.scroller.currentOffset().yOffset;
      yOffset <= Constants.MAIN_SCROLLER_OFFSET_Y_ZERO ? this.negativeOffsetY = yOffset :
      Constants.MAIN_SCROLLER_OFFSET_Y_ZERO;
      // 判断导航栏和状态栏背景透明度变化
      yOffset >= Constants.MAIN_SCROLLER_OFFSET_Y_MAX + this.statusBarHeight ?
        this.navigateBarOpacity = Constants.NAVIGATION_BAR_OPACITY_MAX :
        this.navigateBarOpacity = Constants.NAVIGATION_BAR_OPACITY_MIN;
      this.navigateBarOpacity = yOffset / Constants.MAIN_SCROLLER_OFFSET_Y_MAX;
      // 判断当前的导航栏和图标颜色变化
      yOffset > this.statusBarHeight ?
        this.isWhiteColor = false : this.isWhiteColor = true;
      // 判断状态栏字体颜色变化
      yOffset > this.statusBarHeight ?
      this.windowModel.setSystemBarContentColor(Constants.StatusBarContentBlackColor) :
      this.windowModel.setSystemBarContentColor(Constants.StatusBarContentWhiteColor);
      // 判断导航栏动效变化
      yOffset >= this.statusBarHeight + Constants.MAIN_SCROLLER_OFFSET_STATUS_CHANGE ?
        this.isFlow = true : this.isFlow = false;
    })
    

总结:

本示例使用了LazyForEach进行数据懒加载,LazyForEach懒加载可以通过设置cachedCount属性来指定缓存数量,同时搭配组件复用能力以达到性能最优效果。


如果你想系统性学习 或者准备考取 华为官方开发者认证 ,请加入我的班级:

HarmonyOS开发者学堂

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐