鸿蒙ArkTs开发,仿抖音个人中心header 下拉放大

发布于:2024-05-09 ⋅ 阅读:(40) ⋅ 点赞:(0)

如果是iOS 或者android 上实现,可以用Scollview 的contentOffset 来实现,然而在鸿蒙ets中该如何实现?废话不多说开始撸代码

第一步、实现一个header

// 创建header,准备一张背景图片
  @Builder
  HeaderBuilder(){
    Column() {
      Row() {
        Image($r('app.media.back'))
          .width(25)
          .height(25)
          .onClick(() => {
            router.back();
          })
        Text(this.distance == 0 ? 'test1' : "")
          .fontColor(Color.Black)
          .fontSize(20)
          .margin({ left: 5 })
        Blank()
        Image($r('app.media.share'))
          .width(25)
          .height(25)

        Image($r('app.media.more'))
          .width(25)
          .height(25)

      }
      .width('100%')
      .padding(20)
      .margin({ top: 20 })

      Row() {
        Text(this.distance > 0 ? 'test2' : '')
          .fontColor(Color.Red)
          .fontSize(30)
          .margin({ left: 5 })
      }
      .width("100%")
      .height(35)
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.Start)
    }
    .height(this.ImHeight)
    .width(this.ImWidth)
    .align(Alignment.Center)
    .backgroundImage($r('app.media.banner'))
    .backgroundImageSize(ImageSize.Cover)
  }

 第二步、创建header下方的内容部分,通过下拉下面的部分来实现header 背景图放大,松开后复原

这里小编通过TouchEvent 事件来实现具体代码如下:

.onTouch((event: TouchEvent) => {
        var y = event.touches[0].y
        if (event.type === TouchType.Down) {
          this.duration = 1000;
          this.startY = y;

        }
        if (event.type === TouchType.Up) {
          this.duration = 500;
          this.ImHeight = 200
          this.ImWidth = "100%"
          this.distance = 0
        }
        if (event.type === TouchType.Move) {
          this.distance = event.touches[0].y - this.startY
          if (Math.abs(this.distance) <= 100) {
            console.log("height=>"+ this.ImHeight +  "distance= ", this.distance)
            var height = 200 + this.distance
            if (height <= 0) {
              height = 0
            }else {
              var scale = this.distance / 200;
              this.ImHeight = height
              console.log("height=>"+ this.ImHeight +  "distance= ", this.distance)
              var imgWidth = 100 + scale * 100 + '%'
              if (100 + scale * 100 < 100){
                imgWidth = '100%'
                this.offX = -25 + this.distance
              }else {
                this.offX = -25
              }
              this.ImWidth = imgWidth
            }
          }else{
            this.distance = 0
          }
        }
      })

然而只有手势虽然能实现滑动,但是效果不好,没有bounce 感!如何让他有bounce 感?需要使用动画,具体代码如下:

.animation({
        duration: this.duration,
        curve: Curve.FastOutSlowIn,
        delay: 0,
        iterations: 1,
        playMode: PlayMode.Normal
      })

以上代码基本上是实现本功能的核心部分,完整的代码如下:

// 可拖动子组件,动画,圆弧
      Column() {
        Row() {
          Text('当点击此场景卡片时:')
            .fontSize(16)
          Blank()
          Image($r('app.media.menu'))
            .width(30)
            .height(30)
        }
        .width('100%')
        .margin({ top: 10, left: 10, right: 10, bottom: 20 })
      }
      .offset({y: this.offX})
      .borderRadius(35)
      .padding(20)
      .onTouch((event: TouchEvent) => {
        var y = event.touches[0].y
        if (event.type === TouchType.Down) {
          this.duration = 1000;
          this.startY = y;

        }
        if (event.type === TouchType.Up) {
          this.duration = 500;
          this.ImHeight = 200
          this.ImWidth = "100%"
          this.distance = 0
        }
        if (event.type === TouchType.Move) {
          this.distance = event.touches[0].y - this.startY
          if (Math.abs(this.distance) <= 100) {
            console.log("height=>"+ this.ImHeight +  "distance= ", this.distance)
            var height = 200 + this.distance
            if (height <= 0) {
              height = 0
            }else {
              var scale = this.distance / 200;
              this.ImHeight = height
              console.log("height=>"+ this.ImHeight +  "distance= ", this.distance)
              var imgWidth = 100 + scale * 100 + '%'
              if (100 + scale * 100 < 100){
                imgWidth = '100%'
                this.offX = -25 + this.distance
              }else {
                this.offX = -25
              }
              this.ImWidth = imgWidth
            }
          }else{
            this.distance = 0
          }
        }
      })
      .height('100%')
      .animation({
        duration: this.duration,
        curve: Curve.FastOutSlowIn,
        delay: 0,
        iterations: 1,
        playMode: PlayMode.Normal
      })
      .linearGradient(
        {
          direction: GradientDirection.Top,
          angle: 180,
          colors: [['#c7e2eb', 0.01], ["#F7F7F7", 0.05], ["#F7F7F7", 1]]
        })
     }
    .justifyContent(FlexAlign.Start)

下面是本案列的全部代码,仅供参考:

@Preview
@Entry
@Component
struct DetailPage {
  @State duration: number = 1000
  @State ImHeight: number = 200
  @State ImWidth: string = '100%'
  @State distance: number = 0
  @State offX: number = -25
  private startY = 0

  // 创建header,准备一张背景图片
  @Builder
  HeaderBuilder(){
    Column() {
      Row() {
        Image($r('app.media.back'))
          .width(25)
          .height(25)
          .onClick(() => {
            router.back();
          })
        Text(this.distance == 0 ? 'test1' : "")
          .fontColor(Color.Black)
          .fontSize(20)
          .margin({ left: 5 })
        Blank()
        Image($r('app.media.share'))
          .width(25)
          .height(25)

        Image($r('app.media.more'))
          .width(25)
          .height(25)

      }
      .width('100%')
      .padding(20)
      .margin({ top: 20 })

      Row() {
        Text(this.distance > 0 ? 'test2' : '')
          .fontColor(Color.Red)
          .fontSize(30)
          .margin({ left: 5 })
      }
      .width("100%")
      .height(35)
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.Start)
    }
    .height(this.ImHeight)
    .width(this.ImWidth)
    .align(Alignment.Center)
    .backgroundImage($r('app.media.banner'))
    .backgroundImageSize(ImageSize.Cover)
  }


  build() {
    Column() {
      // header
      this.HeaderBuilder()
      // 可拖动子组件,动画,圆弧
      Column() {
        Row() {
          Text('当点击此场景卡片时:')
            .fontSize(16)
          Blank()
          Image($r('app.media.menu'))
            .width(30)
            .height(30)
        }
        .width('100%')
        .margin({ top: 10, left: 10, right: 10, bottom: 20 })
      }
      .offset({y: this.offX})
      .borderRadius(35)
      .padding(20)
      .onTouch((event: TouchEvent) => {
        var y = event.touches[0].y
        if (event.type === TouchType.Down) {
          this.duration = 1000;
          this.startY = y;

        }
        if (event.type === TouchType.Up) {
          this.duration = 500;
          this.ImHeight = 200
          this.ImWidth = "100%"
          this.distance = 0
        }
        if (event.type === TouchType.Move) {
          this.distance = event.touches[0].y - this.startY
          if (Math.abs(this.distance) <= 100) {
            console.log("height=>"+ this.ImHeight +  "distance= ", this.distance)
            var height = 200 + this.distance
            if (height <= 0) {
              height = 0
            }else {
              var scale = this.distance / 200;
              this.ImHeight = height
              console.log("height=>"+ this.ImHeight +  "distance= ", this.distance)
              var imgWidth = 100 + scale * 100 + '%'
              if (100 + scale * 100 < 100){
                imgWidth = '100%'
                this.offX = -25 + this.distance
              }else {
                this.offX = -25
              }
              this.ImWidth = imgWidth
            }
          }else{
            this.distance = 0
          }
        }
      })
      .height('100%')
      .animation({
        duration: this.duration,
        curve: Curve.FastOutSlowIn,
        delay: 0,
        iterations: 1,
        playMode: PlayMode.Normal
      })
      .linearGradient(
        {
          direction: GradientDirection.Top,
          angle: 180,
          colors: [['#c7e2eb', 0.01], ["#F7F7F7", 0.05], ["#F7F7F7", 1]]
        })
     }
    .justifyContent(FlexAlign.Start)
  }
}