HarmonyOS开发实战:编写一个鸿蒙版的搜索框

46 篇文章 0 订阅
46 篇文章 0 订阅

介绍

在各大 APP 的搜索框中,经常能看到推荐词轮播展示的效果。在 Android 开发中,可以使用 TextSwitcher 组件轻松实现该效果,也可以写两个 TextView 来做轮播动效。下面我们来写一个鸿蒙版本的。

效果预览

分析

功能比较简单,主要就是两个 Text 循环做动效,通过一个 boolean 类型的 flag 来标记当前轮次。

flag = trueflag = flaseflag = true
Text1 向上位移 + 渐隐Text2 向上位移 + 渐隐Text1 向上位移 + 渐隐
Text2 设置成新的词 + 向上位移 + 渐现Text1 设置成新的词 + 向上位移 + 渐现Text2 设置成新的词 + 向上位移 + 渐现

代码实现

首先,创建一个 TextSwitcher.ets,根容器可以用 Stack ,里面放入 2 个 Text 组件。

// TextSwitcher.ets
@Component
export struct TextSwitcher {
  build() {
    Stack() {
      Text("text1")
        .fontColor(Color.Gray)
        .fontWeight(FontWeight.Bold)
        .height('100%')
      Text("text2")
        .fontColor(Color.Gray)
        .fontWeight(FontWeight.Bold)
        .height('100%')
    }
    .alignContent(Alignment.Start)
  }
}

添加后效果如图

 

下面我们来添加动画,动画可以使用 animateTo 来实现。在组件的 aboutToAppear 生命周期中通过setInterval设置每间隔 interval秒触发一次动画。代码如下:

// TextSwitcher.ets
@Entry
@Component
export struct TextSwitcher {

  // 移动距离,每次从 transDistance 移动到 0 再移动到 -transDistance
  @State transDistance: number = 26
  // 动画持续时间
  @State animDuration: number = 500
  // 动画间隔
  @State interval: number = 2000
  
  // Text1 的 位移距离
  @State private trans1: number = 0
  // Text2 的 位移距离
  @State private trans2: number = this.transDistance
  // Text1 的 透明度
  @State private alpha1: number = 1
  // Text2 的 透明度
  @State private alpha2: number = 0
  // 标志位,用于判断当前是 Text1 还是 Text2 移动到中间
  @State private flag: boolean = true

  aboutToAppear(): void {
    setInterval(() => {
      animateTo({
        duration: this.animDuration,
        onFinish: () => {
          // 动画结束后,要把移动到容器上方的 Text 再移动至容器下方
          if (this.flag) {
            this.trans1 = this.transDistance
          } else {
            this.trans2 = this.transDistance
          }
          this.flag = !this.flag
        }
      }, () => {
        if (this.flag) {
          this.trans1 = -this.transDistance
          this.trans2 = 0
          this.alpha1 = 0
          this.alpha2 = 1
        } else {
          this.trans1 = 0
          this.trans2 = -this.transDistance
          this.alpha1 = 1
          this.alpha2 = 0
        }
      })
    }, this.interval)
  }


  build() {
    Stack() {
      Text("text1")
        .fontColor(Color.Gray)
        .fontWeight(FontWeight.Bold)
        .height('100%')
        .translate({ y: this.trans1 })
        .opacity(this.alpha1)
      Text("text2")
        .fontColor(Color.Gray)
        .fontWeight(FontWeight.Bold)
        .height('100%')
        .translate({ y: this.trans2 })
        .opacity(this.alpha2)
    }
    .alignContent(Alignment.Start)
  }
}

效果如下

下面增加文字切换

// TextSwitcher.ets 
...
private index: number = 0
@Prop list: string[] = []
@State private text1: string = this.list[this.index % this.list.length]
@State private text2: string = ""


aboutToAppear(): void {
  setInterval(() => {
    animateTo({
      ...
    }, () => {
      if (this.flag) {
        ...
        this.text2 = this.list[(this.index + 1) % this.list.length]
      } else {
        ...
        this.text1 = this.list[(this.index + 1) % this.list.length]
      }
    })
  }, this.interval)
}


build() {
  Stack() {
    Text(this.text1)
      ...
    Text(this.text2)
      ...
  }
  .alignContent(Alignment.Start)
}

最后,增加入口页面,上完整代码。

// Index.ets
import { TextSwitcher } from '../components/TextSwitcher'

@Entry
@Component
struct Index {
  @State list: string[] = ["推荐词 1", "推荐词 2", "推荐词 3"]

  build() {
    Column() {
      TextSwitcher({ list: this.list })
        .width('100%')
        .height(40)
        .borderRadius(20)
        .backgroundColor('#22232323')

      Button('切换推荐词').onClick(() => {
        this.list = ["Hello World", "Hello HarmonyOS"]
      }).margin(20).stateStyles({
        pressed: {
          .backgroundColor("#33003cff")
        },
        normal: {
          .backgroundColor("#003cff")
        }
      })
    }
    .margin(20)
  }
}

// TextSwitcher.ets
@Component
export struct TextSwitcher {

  private index: number = 0
  @Prop list: string[] = []
  @State private text1: string = this.list[this.index % this.list.length]
  @State private text2: string = ""

  // 移动距离,每次从 transDistance 移动到 0 再移动到 -transDistance
  @State transDistance: number = 26
  // 动画持续时间
  @State animDuration: number = 500
  // 动画间隔
  @State interval: number = 2000

  // Text1 的 位移距离
  @State private trans1: number = 0
  // Text2 的 位移距离
  @State private trans2: number = this.transDistance
  // Text1 的 透明度
  @State private alpha1: number = 1
  // Text2 的 透明度
  @State private alpha2: number = 0
  // 标志位,用于判断当前是 Text1 还是 Text2 移动到中间
  @State private flag: boolean = true

  aboutToAppear(): void {
    setInterval(() => {
      animateTo({
        duration: this.animDuration,
        onFinish: () => {
          // 动画结束后,要把移动到容器上方的 Text 再移动至容器下方
          if (this.flag) {
            this.trans1 = this.transDistance
          } else {
            this.trans2 = this.transDistance
          }
          this.flag = !this.flag
          this.index++
        }
      }, () => {
        if (this.flag) {
          this.trans1 = -this.transDistance
          this.trans2 = 0
          this.alpha1 = 0
          this.alpha2 = 1
          this.text2 = this.list[(this.index + 1) % this.list.length]
        } else {
          this.trans1 = 0
          this.trans2 = -this.transDistance
          this.alpha1 = 1
          this.alpha2 = 0
          this.text1 = this.list[(this.index + 1) % this.list.length]
        }
      })
    }, this.interval)
  }


  build() {
    Stack() {
      Text(this.text1)
        .fontColor(Color.Gray)
        .fontWeight(FontWeight.Bold)
        .height('100%')
        .translate({ y: this.trans1 })
        .opacity(this.alpha1)
      Text(this.text2)
        .fontColor(Color.Gray)
        .fontWeight(FontWeight.Bold)
        .height('100%')
        .translate({ y: this.trans2 })
        .opacity(this.alpha2)
    }
    .alignContent(Alignment.Start)
    .padding({ left: 20, right: 20 })
    .clip(true)
  }
}

知识点总结

  • 层叠布局 Stack ,有点类似于 Android 中的 FrameLayout
  • 文本组件 Text ,类似于 Android 中的 TextView
  • 显式动画 animateTo,类似于 Android 中的属性动画
  • 组件生命周期 aboutToAppear,在组件即将出现时回调。具体时机为在创建自定义组件的新实例后,在执行其 build() 函数之前执行。
  • 组件的 translate 属性,类似 Android 的 translationXtranslationY
  • 组件的 opacity 属性,类似 Android 的 alpha
  • @State 装饰器,组件内状态同步
  • @Prop 装饰器,父组件向子组件单向同步

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习

点击领取→纯血鸿蒙Next全套最新学习资料希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取~~

一、鸿蒙(HarmonyOS NEXT)最新学习路线

​​

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)…等技术知识点。

获取以上完整版高清,请点击→纯血版全套鸿蒙HarmonyOS学习资料

二、HarmonyOS Next 最新全套视频教程

​​

三、《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

​​

四、大厂面试必问面试题

​​

五、鸿蒙南向开发技术

​​

六、鸿蒙APP开发必备

​​
完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结
总的来说,对于大家来说ye是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

                        

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值