【鸿蒙】状态栏的显隐和标题栏随滑动减增元组【感谢各位大佬支持粉丝数超过2万】

预效果如下:

1、状态栏显隐变化:
在这里插入图片描述
2、标题栏随滑动减增元组
在这里插入图片描述

额外需要的设定条件:
1、一般都会开启沉浸式标题栏设置

 const win = await window.getLastWindow(getContext()) //使用window这个API的getLastWindow方法获取页面
    win.setWindowLayoutFullScreen(false) //使用setWindowLayoutFullScreen设置true开启沉浸式模式

    window.getLastWindow(getContext(this),(err:BusinessError,currentWindow:window.Window)=>{
    this.statusBarHeight = px2vp(currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height)
    // })

【最佳实践】是在页面生命周期里选择onPageShow()开启沉浸式效果,onPageHide()里关闭沉浸式效果。避免沉浸式效果干扰其他页面的状态栏和标题栏因为沉浸式设置导致的重叠错乱异常

效果实现代码举例

大部分的首页和主页的标题栏和状态栏需求效果都有细微的区别和差异;所以参考意义比较大一些。不要直接复制到生产工程里,先在练习项目里调试出大差不差的交互效果然后迁移到生产项目工程里比较合适。首页尤其是带主页首页性质的效果调试起来都需要耗费很长时间的。特别是被需求定制好交互的效果细节的就更费劲了。鸿蒙系统某些特性不支持就很抓狂了。
大致逻辑如下:

  1. 整体页面使用Stack容器+Scroll进行布局,不过也不是必须这样。一般都会有滚动过程中的顶部被覆盖或者随着滚动的效果。顶部的UI叠加处理好即可。某些元组是不动不变的,某些是显示隐藏的,某些字体、颜色、风格变化的等等。
  2. 顶部的高度要固定值,中间滚动内容或者整体滚动页面预留这个高度的留白处理
  3. 向上滚动过程中透明度变化处理,一般在scorll里的滚动回调里进行计算,计算过程参考下面的代码示例。元组动画缩放效果处理等等先进行静态效果处理然后进行渐变处理。这样会更有效率一些。
  4. 有个小技巧细节就是触摸事件因为页面容器组件叠加会导致失效,所以要进行事件冒泡处理:
.onTouchIntercept((event: TouchEvent) => {
        // console.log("OnTouchIntercept + " + JSON.stringify(event));
        if (this.isPolygon(event)) {
          return HitTestMode.None
        }
        return HitTestMode.Default
      })
    }
    .width('100%')
    .height('100%')

  }

  isPolygon(event: TouchEvent) {
    return true;
  }`

附上预览效果的参考代码:

例子1 代码



import { AppRouter } from '@ohos/dynamicsrouter/Index';

// 功能模块结构
interface ItemInfo {
  name: string
  image: Resource
  prompt?: string
}

/**
 * 实现步骤:
 * 1. 在置顶位置使用stack组件添加两层状态栏
 * 2. 通过获取Scroll的偏移量,计算透明度,分别对状态栏的组件设置透明度来实现状态栏的显隐变化效果
 */

@AppRouter({ name: "navigationbarchange/NavigationBarChangeView" })
@Component
export struct NavigationBarChangeView {
  // Scroll的偏移量
  @State scrollOffset: number = 0;
  // 状态栏组件的透明度
  @State headOpacity: number = 0;
  // 是否在顶部的标志
  @State isTop: Boolean = true;
  // 状态栏的背景颜色
  @State titleBackgroundColor: Resource = $r('app.color.ohos_id_color_background');
  // 透明度默认值
  private opacityDefaultValue: number = 1;
  // 透明度计算基数
  private opacityComputeRadix: number = 35;
  // 内容相隔距离
  private columnSpace: number = 15;
  // 创建Scroll对象
  private scroller: Scroller = new Scroller();

  build() {
    Stack() {
      Scroll(this.scroller) {
        Column({space: this.columnSpace}) {
          Text($r('app.string.navigationbarchange_text_welcome'))
            .fontSize($r('app.integer.navigationbarchange_font_size_twenty_two'))
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .textAlign(TextAlign.Start)
            .margin({top: $r('app.integer.navigationbarchange_top_interval_sixty')})

          Text($r('app.string.navigationbarchange_text_new_user_registration'))
            .fontSize($r('app.integer.navigationbarchange_font_size_fourteen'))
            .margin({top: $r('app.integer.navigationbarchange_top_interval_minus_five')})
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .textAlign(TextAlign.Start)

          Button($r('app.string.navigationbarchange_text_load'), { type: ButtonType.Capsule})
            .margin({top: $r('app.integer.navigationbarchange_top_interval_twenty')})
            .fontSize($r('app.integer.navigationbarchange_font_size_eighteen'))
            .height($r('app.integer.navigationbarchange_width_and_height_forty'))
            .width($r('app.integer.navigationbarchange_width_and_height_one_hundred_and_thirty'))
            .position({y: $r('app.integer.navigationbarchange_positionY')})

          // "购物"功能区
          Text($r('app.string.navigationbarchange_text_shopping'))
            .fontColor(Color.Black)
            .fontSize($r('app.integer.navigationbarchange_font_size_twenty'))
            .margin({top: $r('app.integer.navigationbarchange_top_interval_sixty'), bottom: $r('app.integer.navigationbarchange_bottom_interval_minus_five')})
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .textAlign(TextAlign.Center)

          Image($r('app.media.navigationbarchange_shopping'))
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .height($r('app.string.navigationbarchange_width_and_height_twenty_five_percent'))
            .borderRadius($r('app.integer.navigationbarchange_borderRadius_twelve'))

          // "娱乐"功能区
          Text($r('app.string.navigationbarchange_text_happy'))
            .fontColor(Color.Black)
            .fontSize($r('app.integer.navigationbarchange_font_size_twenty'))
            .margin({top: $r('app.integer.navigationbarchange_top_interval_ten'), bottom: $r('app.integer.navigationbarchange_bottom_interval_minus_ten')})
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .textAlign(TextAlign.Center)

          Image($r('app.media.navigationbarchange_happly'))
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .height($r('app.string.navigationbarchange_width_and_height_twenty_five_percent'))
            .borderRadius($r('app.integer.navigationbarchange_borderRadius_twelve'))

          // "休闲"功能区
          Text($r('app.string.navigationbarchange_text_relaxation'))
            .fontColor(Color.Black)
            .fontSize($r('app.integer.navigationbarchange_font_size_twenty'))
            .margin({top: $r('app.integer.navigationbarchange_top_interval_ten'), bottom: $r('app.integer.navigationbarchange_bottom_interval_minus_ten')})
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .textAlign(TextAlign.Center)

          Image($r('app.media.navigationbarchange_relaxation'))
            .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
            .height($r('app.string.navigationbarchange_width_and_height_twenty_five_percent'))
            .borderRadius($r('app.integer.navigationbarchange_borderRadius_twelve'))
            .margin({bottom: $r('app.integer.navigationbarchange_bottom_interval_five')})

        }
        .width($r('app.string.navigationbarchange_width_and_height_ninety_two_percent'))
      }
      .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
      .height($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
      .scrollable(ScrollDirection.Vertical)
      .scrollBar(BarState.Off)
      .edgeEffect(EdgeEffect.None)
      // 高性能知识点:onScroll属于频繁回调接口,应该避免在内部进行冗余和耗时操作,例如避免打印日志
      .onScroll(() => {
        // TODO 知识点:显隐变化效果,获取Scroll偏移量,计算透明度,实现效果
        this.scrollOffset = this.scroller.currentOffset().yOffset;
        if(this.scrollOffset <= this.opacityComputeRadix) {
          this.headOpacity = this.scrollOffset / this.opacityComputeRadix;
        } else {
          this.headOpacity = this.opacityDefaultValue;
        }
      })

      // 添加置顶状态栏
      Header({headOpacity: this.headOpacity, titleBackgroundColor: $r('app.color.ohos_id_color_background'), isTop: false});
      // 添加置顶状态栏
      Header({headOpacity: this.opacityDefaultValue, titleBackgroundColor: $r('app.color.navigationbarchange_transparent_color'), isTop: true});
    }
    .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
    .height($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
    .backgroundColor($r('app.color.navigationbarchange_mine_background'))
    .alignContent(Alignment.Top)
  }
}

// 置顶状态栏实现
@Component
struct  Header{
  // 状态栏组件的透明度
  @Prop headOpacity: number;
  // 状态栏的背景颜色
  @Prop titleBackgroundColor: Resource;
  // 是否在顶部的标志
  @Prop isTop: Boolean;
  // 内容相隔距离
  private columnSpace: number = 15;
  // 组件置顶时透明度
  private opacityTopValue: number = 0;
  // 组件非置顶时透明度
  private opacityUnTopValue: number = 1;

  build() {
    Row() {
      Row({space: this.columnSpace}) {
        Button({ type: ButtonType.Normal}) {
          Image($r('app.media.navigationbarchange_button_setting_configuration'))
            .width($r('app.integer.navigationbarchange_width_and_height_thirty_five'))
            .height($r('app.integer.navigationbarchange_width_and_height_thirty_five'))
        }
        .backgroundColor($r('app.color.navigationbarchange_transparent_color'))

        Button({ type: ButtonType.Normal}) {
          Image($r('app.media.navigationbarchange_button_scan'))
            .width($r('app.integer.navigationbarchange_width_and_height_thirty'))
            .height($r('app.integer.navigationbarchange_width_and_height_thirty'))
        }
        .backgroundColor($r('app.color.navigationbarchange_transparent_color'))
      }
      .justifyContent(FlexAlign.Start)
      .margin({left: $r('app.integer.navigationbarchange_left_interval_value')})
      .width($r('app.string.navigationbarchange_width_and_height_thirty_percent'))

      Text($r('app.string.navigationbarchange_text_mine'))
        .fontColor(Color.Black)
        .fontSize($r('app.integer.navigationbarchange_font_size_twenty_two'))
        .opacity(this.isTop ? this.opacityTopValue : this.opacityUnTopValue)

      Row() {
        Button({ type: ButtonType.Normal}) {
          Image($r('app.media.navigationbarchange_button_customer_service_line'))
            .width($r('app.integer.navigationbarchange_width_and_height_thirty'))
            .height($r('app.integer.navigationbarchange_width_and_height_thirty'))
        }
        .backgroundColor($r('app.color.navigationbarchange_transparent_color'))
      }
      .justifyContent(FlexAlign.End)
      .margin({right: $r('app.integer.navigationbarchange_right_interval_value')})
      .width($r('app.string.navigationbarchange_width_and_height_thirty_percent'))
    }
    .opacity(this.headOpacity)
    .height($r('app.integer.navigationbarchange_width_and_height_sixty'))
    .width($r('app.string.navigationbarchange_width_and_height_one_hundred_percent'))
    .justifyContent(FlexAlign.SpaceAround)
    .backgroundColor(this.titleBackgroundColor)
  }
}

例子2 代码



import promptAction from '@ohos.promptAction';
import { AppRouter } from '@ohos/dynamicsrouter/Index';
import { IconAndDescription, Size } from './model/Util';

const Y_OFFSET130 = 130;
const Y_OFFSET_TOP = 76;
const Y_OFFSET60 = 60;
const Y_OFFSET50 = 50;
const Y_OFFSET40 = 40;
const Y_OFFSET20 = 20;
const FULL_SIZE = 100;
const RACE = 1.56;
const BORDER_RADIUS = 8;
const CARD_WIDTH = 150;
const CARD_HEIGHT = 200;
const SETTING_WIDTH = 24;
const HIT_TEST_BLOCK_THRESHOLD = 0.2;

/**
 * 滑动页面改变顶部个人信息栏显示效果
 * 效果:上滑页面,用户头像逐渐缩小并移动到返回文字的后方,原本展示的用户名/选择身份/设置/客服的文本和图标渐隐,顶部用户名文本渐显
 * 下滑页面,用户头像逐渐放大并向下移动,顶部用户名文本渐隐,下方用户名/选择身份/设置/客服的文本和图标渐显
 */

@AppRouter({ name: "slidetohideanddisplace/SlideToHideAndDisplace" })
@Component
export struct SlideToHideAndDisplace {
  // 用户头像图片后方个人信息相关组件(用户名/选择身份/满意度调查)的透明度
  @State userRowOpacity: number = 1;
  // 返回文字后方的用户名的透明度(进入页面时处于隐藏状态)
  @State userNameOpacity: number = 0;
  // 用户头像图片高度
  @State userImageHeight: number = 50;
  // Scroll组件顶部与上方Row组件(个人信息栏)的上边距
  @State scrollMarginTop: number = 0;
  // 用户头像图片顶部与父组件Row的上边距
  @State userImageMarginTop: number = 0;
  // 用户头像图片左侧与父组件Row的左边距
  @State userImageMarginLeft: number = 0;
  // 订单相关的图标和描述的数据列表
  iconsAndDescriptions1: IconAndDescription[] = [
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_11')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_12')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_13')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_14'))
  ]
  // 粉丝/收藏/关注/历史相关的栏目的图标和描述的数据列表
  iconsAndDescriptions2: IconAndDescription[] = [
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_21')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_22')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_23')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_payment"), $r('app.string.slidetohideanddisplace_icon_and_description_24'))
  ]
  // 商品会场的图标和描述的数据列表
  merchandiseVenue: IconAndDescription[] = [
    new IconAndDescription($r("app.media.slidetohideanddisplace_arc_of_light"), $r('app.string.slidetohideanddisplace_icon_and_description_31')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_arc_of_light"), $r('app.string.slidetohideanddisplace_icon_and_description_32')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_arc_of_light"), $r('app.string.slidetohideanddisplace_icon_and_description_33')),
    new IconAndDescription($r("app.media.slidetohideanddisplace_arc_of_light"), $r('app.string.slidetohideanddisplace_icon_and_description_34')),
  ]
  // 可滑动容器组件的控制器
  scroller: Scroller = new Scroller();

  // 自定义构建函数,将重复使用的UI元素抽象成一个方法。此处样式为:上方图标下方文字
  @Builder
  iconAndDescription(icon: Resource, description: string | Resource, iconSize?: Size, radius?: number) {
    Column() {
      Image(icon)
        .size(iconSize === undefined ? {
          height: $r('app.integer.slidetohideanddisplace_icon_default_height'),
          width: $r('app.integer.slidetohideanddisplace_icon_default_height')
        } : iconSize)
        .borderRadius(radius)
      Text(description)
        .margin({ top: $r('app.integer.slidetohideanddisplace_margin_between_icon_and_description') })
    }
    .onClick(() => {
      promptAction.showToast({ message: description });
    })
  }

  // 自定义构建函数。此处样式为:在Row组件中横向排列IconAndDescription
  @Builder
  customRow(iconsAndDescriptions: IconAndDescription[]) {
    Row() {
      // 性能知识点:此处在Row中横向排列组件,列表项确定、数量较少,且需要一次性加载,因此使用ForEach。在列表项多的情况下,推荐使用LazyForEach
      ForEach(iconsAndDescriptions, (item: IconAndDescription) => {
        Column() {
          this.iconAndDescription(item.icon, item.description)
        }
        .width((FULL_SIZE / iconsAndDescriptions.length).toString() + '%')
      })
    }
    .width($r('app.string.slidetohideanddisplace_size_full'))
    .padding($r('app.integer.slidetohideanddisplace_padding_small'))
    .margin({ top: $r('app.integer.slidetohideanddisplace_margin_small') })
    .backgroundColor($r('app.color.slidetohideanddisplace_color_transparent_aa'))
    .borderRadius($r('app.integer.slidetohideanddisplace_border_radius'))
  }

  // 会员和权益中心栏目
  @Builder
  memberBanner() {
    Row() {
      Column() {
        Text($r('app.string.slidetohideanddisplace_member'))
          .fontSize($r('app.integer.slidetohideanddisplace_font_size_mid'))
          .fontColor($r('app.color.slidetohideanddisplace_member1'))
        Text($r('app.string.slidetohideanddisplace_get_off_your_purchases'))
          .margin({ top: $r('app.integer.slidetohideanddisplace_margin_between_icon_and_description') })
          .fontColor($r('app.color.slidetohideanddisplace_member2'))
      }
      .alignItems(HorizontalAlign.Start)
      .padding($r('app.integer.slidetohideanddisplace_padding_small'))

      Blank() // 在容器主轴方向上自动填充容器空余部分

      Column() {
        Image($r("app.media.slidetohideanddisplace_crown"))
          .size({ width: $r('app.integer.slidetohideanddisplace_icon_default_height'), height: $r('app.integer.slidetohideanddisplace_icon_default_height') })
        Text($r('app.string.slidetohideanddisplace_center_of_right'))
          .margin({ top: $r('app.integer.slidetohideanddisplace_margin_between_icon_and_description') })
          .fontColor($r('app.color.slidetohideanddisplace_member3'))
      }
      .padding($r('app.integer.slidetohideanddisplace_padding_small'))
    }
    .height($r('app.integer.slidetohideanddisplace_height_eighty'))
    .width($r('app.string.slidetohideanddisplace_size_full'))
    .borderRadius($r('app.integer.slidetohideanddisplace_border_radius'))
    .linearGradient({
      angle: 45, // 设置颜色渐变起始角度为顺时针方向45°
      colors: [[0x30fa908a, 0.0], [0x44aaaaa, 0.5], [0x30c2b1fa, 1.0]]
    })
    .onClick(() => {
      promptAction.showToast({ message: $r('app.string.slidetohideanddisplace_member_services') });
    })
  }

  // 橘子购物节会场
  @Builder
  shoppingVenue() {
    Column() {
      Text($r('app.string.slidetohideanddisplace_orange_shopping_festival'))
        .fontSize($r('app.integer.slidetohideanddisplace_margin_mid'))
        .fontColor($r('app.color.slidetohideanddisplace_shopping'))
        .width($r('app.string.slidetohideanddisplace_size_full'))
        .margin({ left: $r('app.integer.slidetohideanddisplace_margin_small'), top: $r('app.integer.slidetohideanddisplace_margin_small') })

      Grid() {
        // 性能知识点:此处在Grid中排列组件,列表项确定、数量较少,且需要一次性加载,因此使用ForEach。在列表项多的情况下,推荐使用LazyForEach
        ForEach(this.merchandiseVenue, (item: IconAndDescription) => {
          GridItem() {
            // 调用自定义构建函数,传入图标/描述/图标尺寸/图片圆角半径
            this.iconAndDescription(item.icon, item.description, new Size(CARD_HEIGHT, CARD_WIDTH), BORDER_RADIUS)
          }
        })
      }
      .columnsTemplate('1fr 1fr') // 将父组件均分为2列
      .rowsGap($r('app.integer.slidetohideanddisplace_margin_small'))
      .width($r('app.string.slidetohideanddisplace_size_full'))
      .height($r('app.integer.slidetohideanddisplace_grid_height'))
      .margin({ top: $r('app.integer.slidetohideanddisplace_margin_small') })
    }
    .backgroundColor($r('app.color.slidetohideanddisplace_color_transparent_55'))
    .margin({ top: $r('app.integer.slidetohideanddisplace_margin_small'), bottom: $r('app.integer.slidetohideanddisplace_margin_small') })
    .borderRadius($r('app.integer.slidetohideanddisplace_border_radius'))
  }

  /**
   * 创建一个Row组件,用来显示用户信息,然后在下面创建一个Scroll组件,用来显示其他内容,
   * 当Scroll滑动时,Row组件隐藏且里面的子组件渐隐
   */
  build() {
    Column() {
      Row() {
        Text($r('app.string.slidetohideanddisplace_back'))
          .onClick(() => {
            promptAction.showToast({ message: $r('app.string.slidetohideanddisplace_back') });
          })
        Text($r("app.string.slidetohideanddisplace_user_name"))
          .margin({ left: $r('app.integer.slidetohideanddisplace_margin_large') })
          .opacity(this.userNameOpacity) // userNameOpacity控制顶部用户名的透明度
        Blank()
        Text($r('app.string.slidetohideanddisplace_settings'))
          .opacity(this.userNameOpacity) // 设置的文字透明度与顶部用户名相同
          .onClick(() => {
            // 当组件的不透明度大于阈值时,响应点击事件,显示文本提示框
            if (this.userNameOpacity > HIT_TEST_BLOCK_THRESHOLD) {
              promptAction.showToast({ message: $r('app.string.slidetohideanddisplace_settings') });
            }
          })
        Text($r('app.string.slidetohideanddisplace_customer_service'))
          .margin({
            left: $r('app.integer.slidetohideanddisplace_margin_small'),
            right: $r('app.integer.slidetohideanddisplace_margin_small')
          })
          .opacity(this.userNameOpacity) // 客服的文字透明度与顶部用户名相同
          .onClick(() => {
            // 当组件的不透明度大于阈值时,响应点击事件,显示文本提示框
            if (this.userNameOpacity > HIT_TEST_BLOCK_THRESHOLD) {
              promptAction.showToast({ message: $r('app.string.slidetohideanddisplace_customer_service') });
            }
          })
      }
      .width($r('app.string.slidetohideanddisplace_size_full'))
      .alignItems(VerticalAlign.Center)

      Row() {
        Image($r("app.media.slidetohideanddisplace_batman"))
          .width(this.userImageHeight)
          .height(this.userImageHeight)// userImageHeight控制头像尺寸
            // userImageMarginTop和userImageMarginLeft控制头像在父容器内的位置
          .margin({ top: this.userImageMarginTop, left: this.userImageMarginLeft })

        Column() {
          Text($r("app.string.slidetohideanddisplace_user_name"))
          Button($r('app.string.slidetohideanddisplace_choose_identity'))
            .height($r('app.integer.slidetohideanddisplace_button_height'))
            .width($r('app.integer.slidetohideanddisplace_button_width'))
            .fontColor(Color.White)
            .margin({ top: $r('app.integer.slidetohideanddisplace_margin_between_icon_and_description') })
            .onClick(() => {
              promptAction.showToast({ message: $r('app.string.slidetohideanddisplace_choose_identity') });
            })
        }
        .alignItems(HorizontalAlign.Start)
        .opacity(this.userRowOpacity) // 控制Row组件的透明度
        .padding($r('app.integer.slidetohideanddisplace_padding_small'))

        Blank() // 在容器主轴方向上自动填充容器空余部分

        Row() {
          this.iconAndDescription($r("app.media.slidetohideanddisplace_setting"), $r('app.string.slidetohideanddisplace_settings'), new Size(SETTING_WIDTH, SETTING_WIDTH))
          this.iconAndDescription($r("app.media.slidetohideanddisplace_dialog"), $r('app.string.slidetohideanddisplace_customer_service'), new Size(SETTING_WIDTH, SETTING_WIDTH))
        }
        .width($r('app.integer.slidetohideanddisplace_height_eighty'))
        .justifyContent(FlexAlign.SpaceBetween)
        .opacity(this.userRowOpacity)
      }
      .height($r('app.integer.slidetohideanddisplace_height_one_hundred'))
      .width($r('app.string.slidetohideanddisplace_size_full'))
      // 当组件的不透明度小于阈值时,阻塞子节点和兄弟节点的触摸测试
      .hitTestBehavior(this.userRowOpacity < HIT_TEST_BLOCK_THRESHOLD ? HitTestMode.Block : HitTestMode.Default)

      // Scroll组件中显示个人信息以外的内容
      Scroll(this.scroller) {
        Column() {
          // 会员和权益中心栏目
          this.memberBanner()
          // 订单信息栏目
          this.customRow(this.iconsAndDescriptions1)
          // 粉丝/收藏/关注/历史栏目
          this.customRow(this.iconsAndDescriptions2)
          // 橘子购物街会场
          this.shoppingVenue()

          Text($r('app.string.slidetohideanddisplace_in_the_end'))
            .fontColor(Color.Grey)
        }
        .width($r('app.string.slidetohideanddisplace_size_full'))
      }
      .layoutWeight(1)
      .margin({ top: this.scrollMarginTop })
      .scrollBar(BarState.Off)
      .onDidScroll(() => {
        // TODO: 知识点: Scroll组件绑定onDidScroll事件,然后在此方法里改变该组件的margin和opacity属性值的大小实现组件移动和隐显
        // 性能知识点: onScroll属于频繁回调,不建议在onScroll做耗时和冗余操作
        const yOffset: number = this.scroller.currentOffset().yOffset;
        this.userRowOpacity = yOffset < Y_OFFSET60 ? 1 - yOffset / Y_OFFSET60 : 0;
        if (yOffset < Y_OFFSET_TOP) {
          this.scrollMarginTop = -yOffset;
          this.userImageHeight = Y_OFFSET50 * (1 - (yOffset / Y_OFFSET130));
          this.userImageMarginTop = -yOffset * RACE;
          this.userImageMarginLeft = Y_OFFSET20 * (yOffset / Y_OFFSET60) * RACE;
          if (yOffset > Y_OFFSET40) {
            this.userNameOpacity = (yOffset - Y_OFFSET40) / Y_OFFSET40;
          } else {
            this.userNameOpacity = 0;
          }
        } else {
          this.userImageHeight = Y_OFFSET50 * (1 - (Y_OFFSET_TOP / Y_OFFSET130));
          this.userImageMarginTop = -Y_OFFSET_TOP * RACE;
          this.userImageMarginLeft = Y_OFFSET20 * (Y_OFFSET_TOP / Y_OFFSET60) * RACE;
          this.userNameOpacity = 1;
        }
      })
    }
    .width($r('app.string.slidetohideanddisplace_size_full'))
    .padding($r('app.integer.slidetohideanddisplace_margin_default'))
    .linearGradient({
      angle: 180, // 渐变方向为从上到下
      colors: [[0xffffff, 0.0], [0xfff1f1, 0.2], [0xffdddd, 0.8], [0xffffff, 1.0]] // 优化底部视觉效果
    })
  }
}

扩展设想

1、标题栏、状态栏以及部分大标题共用同一个背景大图的情况下,在向上滚动过程中,隐藏了大标题,缩小大背景图片作为状态栏和标题栏的背景图。安卓和iOS都有类似效果。这个可以事先实现进行技术储备

=====

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lichong951

你的鼓励决定更新的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值