鸿蒙初学者学习手册(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 中动画功能的强大能力。

相关推荐
Funing72 小时前
FreeRTOS学习day1:Keil 工程配置与 FreeRTOS 链表机制理解
数据结构·学习·链表
心中有国也有家2 小时前
使用 DevEco Studio 配置 Flutter 鸿蒙签名
学习·flutter·华为·harmonyos
灯澜忆梦2 小时前
MySQL 完整学习路线
学习·mysql
如此风景2 小时前
鸿蒙开发状态管理 V2 全部装饰器详解速查表
harmonyos
番茄育学园2 小时前
我的三款主流云存储音乐库实测笔记
笔记·分类·媒体
爱吃大芒果3 小时前
鸿蒙 ArkTS 网络工程进阶:@ohos.net.http 模块下的长连接、超时与防内存泄漏实战
华为·harmonyos
FrameNotWork3 小时前
HarmonyOS 6.0 沉浸式状态栏与安全区域适配实战
华为·harmonyos
绝世番茄3 小时前
鸿蒙原生ArkTS布局方式之Stack+Opacity叠加淡入淡出深度解析
华为·harmonyos·鸿蒙
森林古猿13 小时前
再论斜率优化
c++·学习·算法
心中有国也有家4 小时前
鸿蒙Flutter开发环境从零搭建教程(Windows/macOS双平台·避坑版)
学习·flutter·华为·harmonyos