鸿蒙初学者学习手册(HarmonyOSNext_API14)_UIContext(@ohos.arkui.UIContext (UIContext))

前言

Context是鸿蒙中及其重要的Api包括了非常多的接口和功能,而且在官方文档中也是优先推荐使用Context中的接口

在Stage模型中基本介绍

1. UI实例与窗口的一一关联

  • 在Stage模型中,WindowStageWindow是用于管理窗口的类,它们通过loadContent接口加载页面内容。
  • 当调用loadContent时,系统会创建一个UI实例,这个实例是页面内容的具体表现形式,包括布局、控件、样式等。
  • 这个UI实例被绑定到调用loadContent的窗口上,因此每个窗口都有一个独立的UI实例与之关联。这种一一对应的关系确保了窗口的内容和行为是独立且可管理的。

2. 全局UI接口与UI实例的上下文关联

  • 在Stage模型中,有一些全局的UI接口(例如修改UI样式、更新布局、触发事件等)。
  • 这些接口的执行依赖于具体的UI实例上下文。所谓"上下文",是指当前UI实例的状态、布局、控件等信息。
  • 当调用这些全局UI接口时,系统会通过调用链(即代码的执行路径)追溯到当前的UI实例上下文。例如,如果在一个按钮点击事件中调用全局UI接口,系统会根据事件的来源(按钮所在的UI实例)找到对应的上下文。

3. 非UI页面或异步回调中的问题

  • 在非UI页面(例如纯逻辑代码模块、工具类等)中调用全局UI接口时,由于这些代码没有直接关联到某个UI实例,系统无法通过调用链找到对应的上下文。
  • 在异步回调中(例如定时器回调、网络请求完成后的回调等),调用全局UI接口也可能出现问题。因为异步回调的执行时机和上下文可能与最初调用时的上下文不一致。
  • 如果系统无法找到正确的UI实例上下文,就会导致全局UI接口无法正确执行,从而引发接口执行失败。

4. 解决方法

为了避免这种问题,可以采用以下方法:

  • 在UI页面中调用全局接口:确保全局UI接口的调用发生在与UI实例直接相关的代码中。
  • 手动传递上下文:在异步回调中,可以手动将UI实例的上下文传递给回调函数,以便在回调中正确调用全局UI接口。
  • 使用绑定机制:某些框架支持将异步回调与UI实例绑定,确保回调执行时能够正确找到上下文。

接下来将举一个简单的例子

ts 复制代码
// 定义一个名为 AnimateToExample 的组件,并标记为入口组件 (@Entry) 和可复用组件 (@Component)
@Entry
@Component
struct AnimateToExample {
  // 定义状态变量 widthSize,用于控制按钮的宽度,默认值为 250
  @State widthSize: number = 250

  // 定义状态变量 heightSize,用于控制按钮的高度,默认值为 100
  @State heightSize: number = 100

  // 定义状态变量 rotateAngle,用于控制旋转角度,默认值为 0
  @State rotateAngle: number = 0

  // 定义一个布尔型私有变量 flag,用于切换动画状态
  private flag: boolean = true

  // 定义一个 UIContext 类型的变量 uiContext,用于存储当前的 UI 上下文
  uiContext: UIContext | undefined = undefined;

  // aboutToAppear 方法:在组件即将显示时调用
  aboutToAppear() {
    // 获取当前的 UI 上下文并赋值给 uiContext
    this.uiContext = this.getUIContext();
    if (!this.uiContext) {
      // 如果未成功获取 UI 上下文,则打印警告信息
      console.warn("no uiContext");
      return;
    }
  }

  // build 方法:定义组件的 UI 结构
  build() {
    Column() { // 创建一个垂直布局容器
      Button('change size') // 创建一个按钮,文本为 "change size"
        .width(this.widthSize) // 设置按钮宽度为状态变量 widthSize
        .height(this.heightSize) // 设置按钮高度为状态变量 heightSize
        .margin(30) // 设置外边距为 30
        .onClick(() => { // 点击按钮时触发以下逻辑
          if (this.flag) { // 如果 flag 为 true
            this.uiContext?.animateTo({ // 调用UIContext 的 animateTo 方法执行动画
              duration: 2000, // 动画持续时间为 2000 毫秒
              curve: Curve.EaseOut, // 动画曲线为 EaseOut
              iterations: 1, // 动画循环次数为 1 次
              playMode: PlayMode.Normal, // 动画播放模式为 Normal
              onFinish: () => { // 动画结束时回调
                console.info('play end') // 打印日志 "play end"
              }
            }, () => { // 动画更新逻辑
              this.widthSize = 150 // 修改按钮宽度为 150
              this.heightSize = 60 // 修改按钮高度为 60
            })
          } else { // 如果 flag 为 false
            this.uiContext?.animateTo({}, () => { // 调用 animateTo 方法重置按钮大小
              this.widthSize = 250 // 修改按钮宽度为 250
              this.heightSize = 100 // 修改按钮高度为 100
            })
          }
          this.flag = !this.flag // 切换 flag 的值
        })

      Button('stop rotating') // 创建另一个按钮,文本为 "stop rotating"
        .margin(50) // 设置外边距为 50
        .rotate({ x: 0, y: 0, z: 1, angle: this.rotateAngle }) // 设置按钮的旋转属性
        .onAppear(() => { // 组件出现时触发以下逻辑
          // 开始无限循环的旋转动画
          this.uiContext?.animateTo({// 调用UIContext 的 animateTo 方法执行动画
            duration: 1200, // 动画持续时间为 1200 毫秒
            curve: Curve.Friction, // 动画曲线为 Friction
            delay: 500, // 动画延迟 500 毫秒后开始
            iterations: -1, // 动画无限循环(-1 表示无限)
            playMode: PlayMode.Alternate, // 动画播放模式为 Alternate(来回交替)
            expectedFrameRateRange: { // 设置期望的帧率范围
              min: 10, // 最小帧率为 10
              max: 120, // 最大帧率为 120
              expected: 60, // 期望帧率为 60
            }
          }, () => { // 动画更新逻辑
            this.rotateAngle = 90 // 修改旋转角度为 90 度
          })
        })
        .onClick(() => { // 点击按钮时触发以下逻辑
          this.uiContext?.animateTo({ duration: 0 }, () => { // 停止旋转动画
            this.rotateAngle = 0 // 将旋转角度重置为 0 度
          })
        })
    }.width('100%').margin({ top: 5 }) // 设置列容器宽度为 100%,顶部外边距为 5
  }
}

以下是对于 组件代码解释,以及 UIContext 的作用和使用场景:


组件概述

AnimateToExample 是一个标记为入口组件 (@Entry) 和可复用组件 (@Component) 的结构体,用于展示按钮动画效果。它通过 UIContext 提供的动画 API 实现了按钮大小变化和旋转动画的功能。


关键变量

  1. uiContext: UIContext | undefined = undefined;
    • 定义了一个变量 uiContext,用于存储当前的 UI 上下文。
    • UIContext 是 ArkTS 中的一个重要对象,提供了对动画、生命周期等操作的支持。

生命周期方法

aboutToAppear()
  • 在组件即将显示时调用。

  • UIContext 的获取

    arkts 复制代码
    this.uiContext = this.getUIContext();
    • 调用 getUIContext() 方法获取当前的 UI 上下文,并赋值给 uiContext
    • 如果未成功获取 UI 上下文,则打印警告信息 "no uiContext" 并返回。

UI 结构 (build() 方法)

垂直布局容器 (Column())
  • 创建一个垂直布局容器,包含两个按钮,并设置其宽度为 100% 和顶部外边距为 5。
按钮 1:change size
  • 功能:点击按钮时,按钮的宽度和高度会在两种状态之间切换。

  • UIContext 的使用

    arkts 复制代码
    this.uiContext?.animateTo({
      duration: 2000,
      curve: Curve.EaseOut,
      iterations: 1,
      playMode: PlayMode.Normal,
      onFinish: () => {
        console.info('play end');
      }
    }, () => {
      this.widthSize = 150;
      this.heightSize = 60;
    });
    • 调用 uiContext.animateTo 方法执行动画:
      • duration: 2000:动画持续时间为 2000 毫秒。
      • curve: Curve.EaseOut:动画曲线为 EaseOut
      • iterations: 1:动画循环次数为 1 次。
      • playMode: PlayMode.Normal:动画播放模式为 Normal
      • onFinish:动画结束时回调函数打印日志 "play end"
    • 动画更新逻辑中,修改按钮的宽度为 150,高度为 60
按钮 2:stop rotating
  • 功能:点击按钮时,停止旋转动画并将旋转角度重置为 0。

  • UIContext 的使用

    arkts 复制代码
    this.uiContext?.animateTo({
      duration: 1200,
      curve: Curve.Friction,
      delay: 500,
      iterations: -1,
      playMode: PlayMode.Alternate,
      expectedFrameRateRange: {
        min: 10,
        max: 120,
        expected: 60,
      }
    }, () => {
      this.rotateAngle = 90;
    });
    • 在组件出现时(onAppear 方法),调用 uiContext.animateTo 方法启动无限循环的旋转动画:

      • duration: 1200:动画持续时间为 1200 毫秒。
      • curve: Curve.Friction:动画曲线为 Friction
      • delay: 500:动画延迟 500 毫秒后开始。
      • iterations: -1:动画无限循环(-1 表示无限)。
      • playMode: PlayMode.Alternate:动画播放模式为 Alternate(来回交替)。
      • expectedFrameRateRange:设置期望的帧率范围为 min: 10, max: 120, expected: 60
      • 动画更新逻辑中,修改旋转角度为 90 度。
    • 点击按钮时,调用 uiContext.animateTo 方法停止旋转动画:

      arkts 复制代码
      this.uiContext?.animateTo({ duration: 0 }, () => {
        this.rotateAngle = 0;
      });
      • 设置动画持续时间为 0。
      • 将旋转角度重置为 0 度。

总结

在该组件中,UIContext 的主要作用是提供动画相关的功能支持,具体包括:

  1. 获取上下文 :通过 getUIContext() 方法获取当前的 UI 上下文。
  2. 执行动画 :通过 animateTo 方法实现平滑的动画效果,支持多种参数配置(如 durationcurveiterations 等)。
  3. 动态更新状态 :在动画更新逻辑中,动态修改状态变量(如 widthSizeheightSizerotateAngle),从而实现按钮大小变化和旋转动画的效果。

通过 UIContext 的灵活使用,该组件展示了 ArkTS 中动画功能的强大能力。

相关推荐
前路不黑暗@1 小时前
C语言:操作符详解(二)
c语言·开发语言·经验分享·笔记·学习·学习方法·visual studio
蜡笔小电芯2 小时前
【STM32】STM32H750 CubeMX 配置 USB CDC 虚拟串口笔记
笔记·stm32·嵌入式硬件
xiaoxiaoxiaolll2 小时前
金刚石基植入体新突破!Adv. Funct. Mater. 报道首例增材制造固态摩擦电能量收集器
学习
x.Jessica2 小时前
网络的构成元素
网络·学习·计算机网络
森之鸟2 小时前
flutter项目适配鸿蒙
flutter·华为·harmonyos
快乐zbc2 小时前
数学建模Topsis法笔记
笔记·数学建模
yiqiqukanhaiba2 小时前
STM32学习笔记14-I2C硬件控制
笔记·stm32·学习
悠哉悠哉愿意2 小时前
【Python语法基础学习笔记】if语句
笔记·python·学习
杜子不疼.3 小时前
《Python学习之第三方库:开启无限可能》
开发语言·python·学习
奶糖不太甜3 小时前
鸿蒙图片资源加载全攻略:从基础到性能优化
harmonyos·图片资源