动手学鸿蒙App开发 HarmonyOS(06)时间屏保

前言

本篇实现一种带有背景色黑白渐变呼吸效果 并且带有翻转卡片动效的数字时钟屏保。 随着秒钟卡片的翻转和背景色有节奏的变换,给人一种时间飞逝的压迫感。仿佛也暗示着作者急切得盼望着坐上下班回家的公交车。

有兴趣的同学可以跟着做,但建议不要长时间使用该款时间屏保。看多了以后明显会对精神状态有影响。

效果展示

实现原理

1. 呼吸背景色

背景组件是一块全屏的普通Row, 通过定时器启动动画效果,对组件的brightness属性进行修改。由暗到亮,再由亮到暗分2个阶段完成

brightness number 1.0 为当前组件添加高光效果,入参为高光比例,值为1时没有效果,小于1时亮度变暗,0为全黑,大于1时亮度增加,数值越大亮度越大。取值范围:[0, +∞)**说明:**设置小于0的值时,按值为0处理。从API version 9开始,该接口支持在ArkTS卡片中使用。

关于组件的图像效果其实还有很多其他的属性可以进行修改,可以根据UI需求来使用。具体的属性列表可以参考官方文档: 图像效果

2. 翻转卡片

翻转卡片的实现是由上下两层组件来实现的。 当由定时器触发的动画开始时,下层卡片更新为新的时间。上层卡片开始在y方向的中点开始向后翻转。而下层卡片以y方向-90度开始向上翻转并在卡片正面用户时结束动画。

大家可以尝试其他角度或者动画效果来尝试改变动效。

对时间新值@watch的使用值得新手同学注意,这里通过值的变更来触发动画效果。

代码

时间卡片组件

ts 复制代码
@Component
@Preview
export struct FlipText {
  private textWidth = 90
  private textHeight = 110
  private fontSize = 70
  private defaultBgColor = '#66e6e6e6'
  private textBorderRadius: number = 10;
  // 上层动画角度
  @State angleTop: number = 0
  // 底层动画角度
  @State angleBottom: number = -90
  // 旧值
  @Prop oldValue: string
  // 新值,加入监听
  @Link @Watch('valueChange') newValue: string

  /**
   * 监听新值变化
   */
  valueChange() {
    if (this.oldValue === this.newValue) return
    this.angleTop = 0
    this.startTopAnimate()
    this.startBottomAnimate();
  }

  build() {
    Stack() {
      // 底层文字
      Text(this.newValue)
        .commonStyle(this.fontSize, this.textBorderRadius, this.defaultBgColor)
        .rotate({ x: 1, centerY: '50%', angle: this.angleBottom })

      // 顶层文字动画
      Text(this.oldValue)
        .commonStyle(this.fontSize, this.textBorderRadius, this.defaultBgColor)
        .rotate({ x: 1, centerY: '50%', angle: this.angleTop })
    }
    .width(this.textWidth)
    .height(this.textHeight)
  }

  /**
   * 启动顶层文字动画
   */
  startTopAnimate() {
    animateTo({
      duration: 400,
      onFinish: () => {
        this.angleTop = 0
        this.oldValue = this.newValue
      }
    }, () => {
      this.angleTop = 90
    })
  }

  /**
   * 启动底层文字动画
   */
  startBottomAnimate() {
    animateTo({
      duration: 400,
      onFinish: () => {
        this.angleBottom = -90
        this.oldValue = this.newValue
      }
    }, () => {
      this.angleBottom = 0
    })
  }
}

// Text公共样式
@Extend(Text)
function commonStyle(fontSize: number | string | Resource,
                     borderRadius: Length,
                     bgColor: ResourceColor) {
  .width('100%')
  .height('100%')
  .fontColor(Color.Black)
  .fontSize(fontSize)
  .textAlign(TextAlign.Center)
  .borderRadius(borderRadius)
  .backgroundColor(bgColor)
  .shadow({ radius: 30, color: '#ffacacac', offsetY: 10 })
}

小时,分钟,秒钟 封装到一起

ts 复制代码
import { FlipText } from './FlipText'

@Component
@Preview
export struct TimeFlipView {
  // 小时-旧值
  @State oldHours: string = ''
  // 小时-新值
  @State newHours: string = ''
  // 分钟-旧值
  @State oldMinutes: string = ''
  // 分钟-新值
  @State newMinutes: string = ''
  // 秒数-旧值
  @State oldSeconds: string = ''
  // 秒数-新值
  @State newSeconds: string = ''

  @Builder Colon() {
    Column() {
      Circle().width(8).height(8).fill(Color.Black)
      Circle().width(8).height(8).fill(Color.Black).margin({ top: 10 })
    }.padding(10)
  }

  build() {
    Row() {
      // 翻页组件-显示小时
      FlipText({ oldValue: this.oldHours, newValue: $newHours })
      // 冒号
      this.Colon()
      // 翻页组件-显示分钟
      FlipText({ oldValue: this.oldMinutes, newValue: $newMinutes })
      // 冒号
      this.Colon()
      // 翻页组件-显示秒数
      FlipText({ oldValue: this.oldSeconds, newValue: $newSeconds })
    }
    .justifyContent(FlexAlign.Center)
    // .width('100%')
    // .height('100%')
    .onAppear(() => {
      // 开启定时器
      this.initDate()
      setInterval(() => {
        this.updateDate()
      }, 1000)
    })
  }

  /**
   * 初始化时间
   */
  initDate() {
    let date = new Date()
    // 设置小时
    this.oldHours = this.format(date.getHours())
    // 设置分钟
    this.oldMinutes = this.format(date.getMinutes())
    // 设置秒数
    this.oldSeconds = this.format(date.getSeconds())
    // 设置新的秒数
    this.newSeconds = date.getSeconds() + 1 === 60 ? '00' : this.format(date.getSeconds() + 1)
  }

  /**
   * 更新时间
   */
  updateDate() {
    let date = new Date()
    console.log(`${date.getHours()}时${date.getMinutes()}分${date.getSeconds()}秒`)
    // 当新值改变,才有动画
    if (date.getSeconds() === 59) {
      this.newSeconds = '00'
      this.newMinutes = date.getMinutes() + 1 === 60 ? '00' : this.format(date.getMinutes() + 1)
      if (date.getMinutes() === 59) {
        this.newHours = date.getHours() + 1 === 24 ? '00' : this.format(date.getHours() + 1)
      }
    } else {
      this.newSeconds = this.format(date.getSeconds() + 1)
    }
  }

  /**
   * 不足十位前面补零
   */
  format(param) {
    let value = '' + param
    if (param < 10) {
      value = '0' + param
    }
    return value
  }
}

主页

ts 复制代码
@Entry
@Component
struct Index {
  @State bgBrightness: number = 0.0

  /**
   * 启动背景亮度动画
   */
  startBrightnessAnimate() {
    animateTo({
      duration: 2000,
      onFinish: () => {
        animateTo({
          duration: 400,
          onFinish: () => {
            this.bgBrightness = 0.0
          }
        }, () => {
          this.bgBrightness = 0.0
        })
      }
    }, () => {
      this.bgBrightness = 1.0
    })
  }

  build() {
    Stack() {
      Row()
        .width('100%').height('100%')
        .backgroundColor(Color.White)
        .brightness(this.bgBrightness)
        .onAppear(() => {
          setInterval(() => {
            this.startBrightnessAnimate()
          }, 2500)
      })
      Row() {
        TimeFlipView()
      }
      .alignItems(VerticalAlign.Center)
    }
  }
}

总结

眼睛有点花了已经开始,写这个系列非常不容易,就像每天不知道中午点什么外卖,需要耗费许多想象力。

望各位耗子尾汁,点赞关注收藏三连。感谢大家!下次见~

相关推荐
编程百晓君1 小时前
一文彻底拿捏DevEco Studio的使用小技巧
华为·harmonyos
敲代码敲到头发茂密1 小时前
【大语言模型】LangChain 核心模块介绍(Memorys)
android·语言模型·langchain
H1002 小时前
重构(二)
android·重构
轻口味2 小时前
【每日学点鸿蒙知识】私仓搭建、resources创建文件夹、hvigor如何动态设置版本、SM3摘要算法、SP存储报错等
华为·json·harmonyos
拓端研究室3 小时前
R基于贝叶斯加法回归树BART、MCMC的DLNM分布滞后非线性模型分析母婴PM2.5暴露与出生体重数据及GAM模型对比、关键窗口识别
android·开发语言·kotlin
zhangphil3 小时前
Android简洁缩放Matrix实现图像马赛克,Kotlin
android·kotlin
m0_512744643 小时前
极客大挑战2024-web-wp(详细)
android·前端
JasonYin~4 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---查看国际航班服务
华为·harmonyos
lw向北.4 小时前
Qt For Android之环境搭建(Qt 5.12.11 Qt下载SDK的处理方案)
android·开发语言·qt
深海的鲸同学 luvi4 小时前
【HarmonyOS NEXT】hdc环境变量配置
linux·windows·harmonyos