HarmonyOsArkUI-仿京东头部动画效果

1,692 阅读3分钟

本文正在参加华为鸿蒙有奖征文征文活动

HarmonyOS.png

版本环境

API版本:9
DevStudio版本: DevEco Studio 4.1 Release Build Version: 4.1.0.400, built on April 9, 2024 Build #DS-223.8617.56.36.410400 Runtime version: 17.0.6+10-b829.5 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. Windows 11 10.0 GC: G1 Young Generation, G1 Old Generation Memory: 1536M Cores: 16。
模拟器:Remote Emulator P50 api9 arm

emulator.png

吐吐:由于本电脑死活无法启动本地模拟器,so改用远程模拟器,可是远程模拟器如上图所示,经常没有资源可用,Unable to apply for a remote emulator: No device available. Please try again later.。。。


资料指南

相关资料和官网权限

  1. 官网首页:www.harmonyos.com/
  2. HarmonyOS代码仓库:gitee.com/openharmony
  3. API指南:developer.huawei.com/consumer/cn…
  4. 应用开发指南:developer.huawei.com/consumer/cn…
  5. DevStudio下载相关:developer.huawei.com/consumer/cn…

开发

作为应用首页场景,经常会有些创意实现,首页支撑这很多数据,常常是一个可滑动列表展示数据,头部固定搜索框方便用户直达想要的内容,使用一些动画处理可以吸晴用户。

应用布局:

Tabs切换实现应用界面框架

 Tabs({barPosition:BarPosition.End,controller:this.mTabController}){
        TabContent(){
          HomeView()
        }.tabBar(this.TabBuilder("首页",0,$r('app.media.macbook'),$r('app.media.one_normal')))


        TabContent(){
          SecondView()
        }.tabBar(this.TabBuilder("种草",1,$r('app.media.book'),$r('app.media.two_normal')))

…      })

首页布局代码:自定义头部View+ 可滑动列表List+LazyForEach懒加载数据

Column() {
  this.headerView()
  List({ space: 10 }) {
    LazyForEach(mDataModel.mBaseDataSource, (item: BaseData, index: number) => {
      ListItem() {
        if (item as Article) {
          if (index === 0) {
            BannerView()
          } else {
            Text(index + " - " + (item as Article).title)
              .width('80%')
              .height('40vp')
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }

        }
      }
      .width('100%')
    })
  }
  .width('100%')
  .height('100%')
  //要用权重,不然高度会有问题
  .layoutWeight(1)
  .edgeEffect(EdgeEffect.Fade) // 必须设置列表为滑动到边缘无效果
  .parallelGesture(PanGesture(this.panOption)
    .onActionStart((event: GestureEvent) => {
      this.touchYOld = event.offsetX
      //  console.log(TAG,"onActionStart y:"+this.touchYOld)
    })

    .onActionUpdate((event: GestureEvent) => {
      this.onActionUpdate(event)
      //  console.log(TAG,"onActionUpdate y:"+event.offsetY)
    })

    .onActionEnd((event: GestureEvent) => {

    })
  )

注意:TabContent 包裹 Column{View()+ List().height('100%')},其中List 要使用权重为1,撑满布局,即layoutWeight(1).不然List高度会有问题

静态效果:

Screenshot_20240611173734691.png Screenshot_20240611173816402.png Screenshot_20240611174436698.png Screenshot_20240611173832068.png

动态效果:

hhps.gif

实现思路:

头部View跟随List滑动,折叠、伸展,然后搜索框部分进行缩放。List进行手势监听,在滑动过程中对Y轴进行处理,头部View改变高度,MarginTop改变,手势上推下拉判断等,整体代码如下:

private onActionUpdate(event: GestureEvent) {
  this.touchYNew = event.offsetY;

  let distanceY = this.touchYNew - this.touchYOld;
  // 当前手势是否下拉
  let isPullAction = distanceY > 0;

  console.log(TAG, "是否上拉:" + isPullAction + ` Y:${distanceY}`)

  let marginTopY = this.mRowHeight + distanceY
  

  if (isPullAction) {
    let titleTopY = this.headerViewHeight + distanceY
    //----------------下拉--------------
    //stack margin 变化
    if (marginTopY < 58) {
      this.mRowHeight = marginTopY
    } else {
      if (this.mRowHeight != 58) {
        this.mRowHeight = 58
      }
    }
    //headerView 高度变化
    if (titleTopY < 100) {
      this.headerViewHeight = titleTopY
      this.mRowWidth = 70 + 20 * (50 / titleTopY)
    } else {
      if (this.headerViewHeight != 100) {
        this.headerViewHeight = 100
        this.mRowWidth = 90
      }
    }
    console.debug(TAG, "titleTopY:" + titleTopY)

  } else {
    let titleTopY = this.tileHeight + distanceY
    //----------------上推-----------
    //stack margin 变化
    if (marginTopY > 0) {
      this.mRowHeight = marginTopY
    } else {
      if (this.mRowHeight != 8) {
        this.mRowHeight = 8
      }
    }
    //headerView 高度变化
    if (titleTopY > 50) {
      this.headerViewHeight = titleTopY
      this.mRowWidth = 90 - 20 * (50 / titleTopY)
    } else {
      if (this.headerViewHeight != 50) {
        this.headerViewHeight = 50
        this.mRowWidth = 70
      }
    }


    console.debug(TAG, "titleTopY:" + titleTopY)
  }
}

还要处理搜索框跟随Y轴进行横向伸缩变化,下拉横向变化处理: 宽度 + 可伸缩最大值 * (整体高度 / 高度差变化) , 处理横向伸缩变化。上推则反之处理

总结

通过本次Demo学习,HarmonyOS ArkUI 代码实现布局还是蛮直观的,这次难度中等,主要是实现手势处理,通过滑动List.parallelGesture滑动监听,滑动开始、滑动中、滑动结束处理View高度变化和横向变化处理。官方方法实现简单处理即可得出要想的效果,如果再要实现复杂的可根据自己的效果进行处理,实现方便,代码可读性强。相比Android滑动处理要简单很多了。
鄙人还在学习中有不足,望大佬们多多指教,没有最新API权限有点无奈~