鸿蒙Next学习-悬浮窗口/拖动/吸边

news2024/12/26 19:18:01

实现了一个可以拖拽的悬浮球组件,支持自动贴边和隐藏等功能,适用于窗口场景。以下是对其功能的详细描述:

1. 组件介绍

该悬浮球(FloatBall)组件是一种浮动在窗口中的 UI 元素,用户可以通过拖动该元素,在屏幕上自由移动。同时,组件支持自动隐藏和自动贴边的功能,当用户不操作悬浮球时,它可以半透明隐藏或者贴靠屏幕的边缘。该组件设计为通用,可以在鸿蒙系统中应用于各种场景。

2. 状态变量

组件中使用了多个状态变量来控制悬浮球的显示、移动和透明度等功能:

  • statusHeight:状态栏的高度,用于计算窗口内有效区域。
  • bottomAvoidAreaHeight:底部规避区域的高度,防止悬浮球被遮挡。
  • curLeftcurTop:当前悬浮球的相对于窗口左上角的横纵坐标。
  • opacityN:悬浮球的透明度,通过该变量控制悬浮球在不同状态下的显示效果。

3. 移动与触摸控制

该组件实现了悬浮球的拖动功能,通过监听触摸事件(onTouch)来响应用户操作。代码中的逻辑包括:

  • 记录触摸按下时悬浮球的位置和触摸点的坐标。
  • 根据用户的拖动,实时更新悬浮球的位置,并限制其在屏幕边界范围内移动。
  • 松开手指后,根据设置,悬浮球会自动隐藏或者贴边。

4. 自动隐藏和贴边功能

该组件支持自动隐藏和自动贴边两种特性,分别在用户不操作时触发:

  • 自动隐藏:在一段时间后悬浮球会逐渐变为半透明并隐藏,隐藏的时间间隔可以通过 aotoHideTime 属性来配置。
  • 自动贴边:悬浮球松开后会自动靠近最近的屏幕边缘,通过动画完成平滑的贴边操作,贴边超时时间通过 aotoEdgingTime 配置。

5. 生命周期方法

aboutToAppear() 方法在组件初始化时调用,负责获取当前窗口的信息,例如状态栏高度、规避区域高度、窗口宽度等,并根据这些信息设置悬浮球的初始位置(默认为屏幕右下角)。

6. 透明度控制

组件支持透明度变化,当用户操作悬浮球时,透明度恢复为默认值 (opacityDefault);当悬浮球进入半隐藏状态时,透明度会降低 (opacityHide)。

7. 事件传递机制

组件可以通过回调函数的方式将点击、隐藏、贴边等事件传递给外部使用者:

  • onClickEvent:悬浮球点击事件。
  • onEdgingEvent:悬浮球贴边事件。
  • onHideEvent:悬浮球隐藏事件。
  • onShowEvent:悬浮球显示事件。

这些事件处理函数允许外部代码在触发相应事件时,执行自定义逻辑。

8. 动画处理

悬浮球的显示、隐藏、以及贴边操作,均通过动画实现,使交互过程更加流畅和友好。代码使用 animateTo 方法,指定动画持续时间,并在动画结束时调用相应的回调函数。

9. 扩展性与定制化

通过该代码,开发者可以方便地修改悬浮球的外观(如图片资源、半径大小),以及其行为(如自动隐藏时间、是否允许超过边界、是否启用拖动等),满足多种应用场景的需求。

悬浮球组件
import { window } from '@kit.ArkUI'

const TAG: string = '[FloatBall]';


/**
 * 悬浮球
 */
@Entry
@Component
export struct FloatBall {
  @State statusHeight: number = 0          // 状态栏高度
  @State bottomAvoidAreaHeight: number = 0 // 手机底部规避区域高度
  @State curLeft: number = 0               // 当前悬浮按钮距离窗口左边距离
  @State curTop: number = 0                // 当前悬浮按钮距离窗口顶部距离
  @State opacityN: number = 0              // 当前透明度
  private startLeft: number = 0            // 开始移动那一刻悬浮按钮距离窗口左边距离
  private startTop: number = 0             // 开始移动那一刻悬浮按钮距离窗口顶部距离
  private startX: number = 0               // 开始移动触摸点x坐标,相对窗口左上角
  private startY: number = 0               // 开始移动触摸点y坐标,相对窗口左上角
  private winWidth: number = 0             // 窗口宽度
  private winHeight: number = 0            // 窗口高度
  private isTouc = false                   // 是否触摸中
  private time = 0                         // 隐藏定时器
  private state = 0                        // 当前状态 0 未处理 1 显示 2 贴边 3 隐藏
  fixedLeft:boolean = false                // 固定左边
  fixedRight:boolean = false               // 固定右边
  image: Resource = null!                  // 图片资源
  radius: number = 25                      // 悬浮按钮半径
  opacityHide: number = 1.0                // 半隐藏后的透明度
  opacityDefault: number = 1.0             // 默认透明度
  marginSart = 25                          // 从隐藏恢复到显示状态的默认边距
  aotoHide = true                          // 开启自动隐藏
  aotoHideTime = 3000                      // 自动隐藏的超时时间
  aotoEdging = true                        // 自动贴边
  enableOutEdging = true                   // 拖拽时允许超过边界
  enableDragWhenHidden = true              // 允许隐藏时直接拖动,如果false,则需要先点击一下,从隐藏状态显示后,才能继续拖动
  aotoEdgingTime = 3000                    // 自动贴边的超时时间
  onClickEvent?: () => boolean;            // 点击事件传递, 如果返回false,则阻止后续事件
  onEdgingEvent?: () => boolean;           // 贴边事件传递, 如果返回false,则阻止后续事件
  onHideEvent?: () => boolean;             // 半隐藏事件传递, 如果返回false,则阻止后续事件
  onShowEvent?: () => boolean;             // 显示事件传递, 如果返回false,则阻止后续事件

  /**
   * 生命周期函数-初始化
   */
  aboutToAppear() {
    // 初始化透明度
    this.opacityN = this.opacityDefault
    // 初始化窗口信息
    this.getWindowInfo()
  }

  /**
   * 获取窗口尺寸信息
   */
  getWindowInfo() {
    window.getLastWindow(getContext(this), (err, windowClass) => {
      if (!err.code) { //状态栏高度
        this.statusHeight = px2vp(windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height)
        //获取手机底部规避区域高度
        this.bottomAvoidAreaHeight =
          px2vp(windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
            .bottomRect
            .height) //获取窗口宽高
        let windowProperties = windowClass.getWindowProperties()
        this.winWidth = px2vp(windowProperties.windowRect.width)
        this.winHeight = px2vp(windowProperties.windowRect.height)
        //设置初始位置位于屏幕右下角,演示设置可根据实际调整
        this.curLeft = 10
        if(this.fixedRight){
          this.curLeft = this.winWidth - this.radius * 2
        } else if(this.fixedLeft){
          this.curLeft = 0
        } else{
          this.curLeft = 10
        }
        this.curTop = this.winHeight * 0.75

        // 开启自动用隐藏
        if (this.aotoHide) {
          this.onHide()
        }
      }
    })
  }

  /**
   * UI 绘制
   */
  build() {
    //悬浮按钮
    Row() {
      Image(this.image).width(this.radius * 2)           // 图片
    }
    .width(this.radius * 2)
    .height(this.radius * 2)
    .justifyContent(FlexAlign.Center)
    .borderRadius(this.radius)
    // .backgroundColor('#E8E8E8')
    .opacity(this.opacityN)                             // 透明度
    .position({ x: this.curLeft, y: this.curTop })      // 位置绑定,注意@State关键词
    .onTouch((event: TouchEvent) => {                   // 手指按下记录初始触摸点坐标、悬浮按钮位置
      if (event.type === TouchType.Down) {
        this.isTouc = true
        console.log('TouchEvent: 按下');
        // 恢复透明度
        this.restoreOpacity()
        this.startX = event.touches[0].windowX
        this.startY = event.touches[0].windowY
        this.startLeft = this.curLeft
        this.startTop = this.curTop
      }                                                 // 按下
      else if (event.type === TouchType.Up) {
        this.isTouc = false
        console.log('TouchEvent: 松开');
        if (this.aotoHide) {                            // 松开后隐藏
          this.onHide()
        } else if (this.aotoEdging) {                   // 松开后贴边
          this.onEdging()
        }
      }
      else if (event.type === TouchType.Move) {         // 拖动
        if(this.state == 3 && !this.enableDragWhenHidden){
          return
        }
        this.isTouc = true
        let touch = event.touches[0]                                        // 获取手指触摸位置
        let curLeft = this.startLeft + (touch.windowX - this.startX)        // 计算悬浮球位置
        // 只有在没固定情况下才能移动
        if(!this.fixedLeft && !this.fixedRight) {
          // 是否允许超过边界
          if(!this.enableOutEdging){
            curLeft = Math.max(0, curLeft)                                    // 限制悬浮球不能移除屏幕右边
            this.curLeft = Math.min(this.winWidth - 2 * this.radius,curLeft)  // 限制悬浮球不能移除屏幕左边
          } else{
            this.curLeft = curLeft
          }
        }
        let curTop = this.startTop + (touch.windowY - this.startY)          // 限制悬浮球不能移除屏幕上边
        curTop = Math.max(0, curTop)                                        // 限制悬浮球不能移除屏幕下边
        this.curTop =
          Math.min(this.winHeight - 2 * this.radius - this.bottomAvoidAreaHeight - this.statusHeight, curTop)
        console.log('TouchEvent: 移动');
      }
    })
    .onClick(() => {
      if (!this.isShow() || this.state == 3) {
        this.onMyShow()
        return
      }
      let fal = false
      if (this.onClickEvent !== undefined) {
        fal = this.onClickEvent();
      }
      if (fal && this.aotoHide) {
        this.onHide();                                                     // 点击完,就继续去隐藏
      }
    })

  }

  public onMyClick2(onClickEvent: () => boolean) {
    this.onClickEvent = onClickEvent
  }

  /**
   * 隐藏
   */
  onHide() {
    // 如果已经是隐藏,就退出
    if (!this.isShow()) {
      return
    }
    // 如果开启了自动贴边,就先判断是否贴边
    if (this.aotoEdging && !this.ifEdging()) {
      // 先执行贴边
      console.log(TAG, "开启了自动贴边, 当前未贴边")
      this.onEdging()
      return
    }
    // 先取消上一个定时器,在搞新的
    if (this.time != 0) {
      console.log(TAG, "清除上次未执行的目标")
      clearTimeout(this.time);
    }
    console.log(TAG, "创建目标: 隐藏")
    this.time = setTimeout(() => {
      console.log(TAG, "进入执行目标: 隐藏")
      this.onMyHideDo()
    }, this.aotoHideTime)
  }

  /**
   * 贴边
   */
  onEdging() {
    // if (this.time != 0) {
    //   console.log(TAG, "清除上次未执行的目标")
      // clearTimeout(this.time)
    // }
    console.log(TAG, "创建目标: 贴边")
    // this.time = setTimeout(() => {
      console.log(TAG, "进入执行目标: 贴边")
      this.onEdgingDo()
    // }, this.aotoEdgingTime)
  }

  /**
   * 执行贴边
   */
  onEdgingDo() {
    if (this.isTouc) {
      // 如果还在触摸中,就往后延时执行
      console.log(TAG, "推后执行目标:在触摸中 贴边")
      this.onEdging()
    } else {
      this.state = 2
      // 隐藏动画
      console.log(TAG, "执行目标:贴边")
      animateTo({
        duration: 1000,
        onFinish: (() => {
          console.log(TAG, "贴边动画结束")
          let fal = true
          // 记得清除定时器资源
          clearTimeout(this.time)
          this.time = 0
          // 传递贴边事件
          if(this.onEdgingEvent !== undefined){
            fal = this.onEdgingEvent()
          }
          // 贴边动画结束 开始准备隐藏
          if (fal && this.aotoHide) {
            this.onHide()
          }
        })
      }, () => {
        // 修改位置
        if (this.curLeft > this.winWidth / 2) {
          this.curLeft = this.winWidth - this.radius * 2
        } else {
          this.curLeft = 0
        }
      })
      // 取消定时器
      if (this.time != 0) {
        clearTimeout(this.time);
        this.time = 0
      }
    }
  }

  /**
   * 执行隐藏动作
   */
  onMyHideDo() {
    if (this.isTouc) {
      // 如果还在触摸中,就往后延时执行
      console.log(TAG, "推后执行目标:在触摸中 隐藏")
      this.onHide()
    } else {
      this.state = 3
      // 隐藏动画
      console.log(TAG, "执行目标:隐藏")
      animateTo({
        duration: 1000,
        onFinish: (() => {
          console.log(TAG, "隐藏动画结束")
          // 记得清除定时器资源
          clearTimeout(this.time)
          this.time = 0
          // 传递隐藏事件
          if(this.onHideEvent !== undefined){
            this.onHideEvent()
          }
        })
      }, () => {
        // 修改透明度
        this.onOpacity()
        // 修改坐标
        if (this.curLeft > this.winWidth / 2) {
          this.curLeft = this.winWidth - this.radius
        } else {
          this.curLeft = 0 - this.radius
        }
      })
      // 取消定时器
      if (this.time != 0) {
        clearTimeout(this.time);
        this.time = 0
      }
    }
  }

  /**
   * 显示
   */
  onMyShow() {
    // 显示动画
    console.log(TAG, "执行目标:显示")
    this.state = 1
    animateTo({
      duration: 500, onFinish: (() => {
        console.log(TAG, "显示动画结束")
        let fal = true
        // 记得清除定时器资源
        clearTimeout(this.time)
        this.time = 0
        if(this.onShowEvent !== undefined){
          fal = this.onShowEvent()
        }
        if(fal){
          // 重新加载隐藏
          this.onHide()
        }
      })
    }, () => {
      // 修改坐标
      if (this.curLeft > this.winWidth / 2) {
        this.curLeft = this.winWidth - this.radius * 2 - this.marginSart
      } else {
        this.curLeft = this.marginSart
      }
    })
    // 显示后,就取消定时器
    if (this.time != 0) {
      clearTimeout(this.time);
      this.time = 0
    }
  }

  /**
   * 启用半透明
   */
  onOpacity(){
    this.opacityN = this.opacityHide
  }

  /**
   * 恢复默认透明度
   */
  restoreOpacity(){
    this.opacityN = this.opacityDefault
  }

  /**
   * 判断是否是隐藏状态
   * @returns
   */
  isShow() {
    if (this.curLeft < 0) {
      return false
    } else if (this.curLeft >= this.winWidth - this.radius) {
      return false
    }
    return true
  }

  /**
   * 判断是否贴边
   * @returns
   */
  ifEdging() {
    if (this.curLeft == 0) {
      return true
    } else if (this.curLeft == this.winWidth - this.radius * 2) {
      return true
    }
    return false
  }
}
父页面 
import { FloatBall } from 'lib_base/src/main/ets/common/view/FloatBall';
import { promptAction } from '@kit.ArkUI';
import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct Index {
  controller: WebviewController = new webview.WebviewController();

  build() {
    Stack() {
      // 一个webview,充当用户业务视图
      Web({ src: "https://www.baidu.com", controller: this.controller })
        .domStorageAccess(true)
        .onlineImageAccess(true)
        .imageAccess(true)
        .zoomAccess(false)                             // 禁止缩放
        .javaScriptAccess(true)                        // 启用js交互
        .backgroundColor(Color.White)                  // 背景
        .width('100%')

      // 悬浮按钮
      FloatBall({
        image: $r('app.media.loading'),             // 图片资源
        radius: 25,                                   // 悬浮按钮半径
        marginSart: 25,                               // 从隐藏恢复到显示状态的默认边距
        aotoEdging: true,                             // 开启自动贴边
        aotoHideTime: 10,
        aotoEdgingTime: 300,
        enableOutEdging: false,
        aotoHide: false,                               // 开启自动隐藏
        opacityHide: 0.5,                             // 半隐藏后的透明度
        onClickEvent: (): boolean => {                // 点击事件
          promptAction.showToast({ message: '点击了悬浮球' });
          if(this.controller.accessStep(-1)){
            this.controller.backward(); // 返回上一个web页
          }
          return true
        },
        onEdgingEvent: (): boolean => {
          promptAction.showToast({ message: '我贴边了' });
          return true
        },
        onHideEvent: (): boolean => {
          promptAction.showToast({ message: '我隐藏了' });
          return true
        },
        onShowEvent: (): boolean => {
          promptAction.showToast({ message: '我显示了' });
          return true
        }
      })
        // .touchable(false)                         // 这个过期了,.hitTestBehavior(HitTestMode.None)代替
        .hitTestBehavior(HitTestMode.None)           // 重要用于点击事件穿透,不然无法点击Web内容
        .width("100%")
        .height("100%")
    }
    .height('100%')
    .width('100%')
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2254293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面向初学者的 Ansys Mechanical 中的接触建模

接触概述 Ansys Mechanical 中的接触建模是仿真结构不同部分在各种条件下如何相互作用的关键方面。它涉及定义表面的接触方式&#xff0c;即它们是接触、滑动还是分离。Ansys Mechanical 提供了广泛的接触选项来准确建模这些交互&#xff0c;包括粘合、摩擦和无分离接触。每个…

【C++指南】C++内存管理 深度解析

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 引言 一、C 内存管理概述 二、C内存区域划分 三、C 内存管理方式 &#x1f343;1.自动内存管理…

聚类算法全面解析:理论与实践结合

聚类&#xff08;Clustering&#xff09;是数据挖掘和机器学习中一类重要的无监督学习方法&#xff0c;旨在将数据划分为多个类别&#xff0c;使得类别内部的数据相似度高&#xff0c;而类别之间的数据差异较大。聚类广泛应用于图像分割、市场分析、生物信息学、文本挖掘等领域…

Python 批量剪辑视频片头片尾工具

Python 批量剪辑视频片头片尾工具 1.简介&#xff1a; 批量剪辑片头片尾的软件&#xff0c;让你的视频创作事半功倍&#xff0c;视频剪辑处理完成后&#xff0c;用户可以在指定文件夹中查看已经剪切完片头片尾的视频‌。这些工具不仅适用于个人用户进行日常的视频编辑工作&am…

大模型分类1—按应用类型

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl根据应用领域,大模型可分为自然语言处理、计算机视觉和多模态大模型。 1. 自然语言处理大模型(NLP) 1.1 应用领域与技术架构 自然语言处理大模型(NLP)的应用领域广泛,包括但不限于文本分类、…

保姆级教程用vite创建vue3项目并初始化添加PrimeVue UI踩坑实录

文章目录 一、什么是PrimeVue二、详细教程1.添加PrimeVue2.配置main.js3.添加自动引入4.配置vite.config.js5.创建测试页面 一、什么是PrimeVue PrimeVue 是一个用于 Vue.js 3.x 开发的一款高质量、广受欢迎的 Web UI 组件库。 官网地址&#xff1a;https://primevue.org/ 二、…

Go的Gin比java的Springboot更加的开箱即用?

前言 隔壁组的云计算零零后女同事&#xff0c;后文简称 云女士 &#xff0c;非说 Go 的 Gin 框架比 Springboot 更加的开箱即用&#xff0c;我心想在 Java 里面 Springboot 已经打遍天下无敌手&#xff0c;这份底蕴岂是 Gin 能比。 但是云女士突出一个执拗&#xff0c;非我要…

php 系统函数 记录

PHP intval() 函数 PHP函数介绍—array_key_exists(): 检查数组中是否存在特定键名 如何使用PHP中的parse_url函数解析URL PHP is_array()函数详解&#xff0c;PHP判断是否为数组 PHP函数介绍&#xff1a;in_array()函数 strpos定义和用法 strpos() 函数查找字符串在另一字符串…

关于Chrome自动同步书签的解决办法

前言 并不一定适用所有用户&#xff0c; 目前我在网上搜集了一些资料&#xff0c;也做了一些尝试。 就我个人总结的经验来讲&#xff0c;分享大家以下几种办法&#xff1a; 1.书签同步插件 点击如下&#x1f517;&#xff1a; Chrome书签同步https://bm.famend.cn/ …

matrixzq:基于ℤq的纯python矩阵库

1. 引言 当希望使用纯 Python 代码对整数 q 模矩阵进行操作&#xff0c;以演示使用学习误差 (Learning-With-Errors&#xff0c;LWE) 的基于格的加密方案的一些原理时&#xff0c;找到了 Thom Ives 编写的优秀代码“纯 Python 中无需 Numpy 或 Scipy 的 BASIC 线性代数工具”&…

深度学习笔记——模型压缩和优化技术(蒸馏、剪枝、量化)

本文详细介绍模型训练完成后的压缩和优化技术&#xff1a;蒸馏、剪枝、量化。 文章目录 1. 知识蒸馏 (Knowledge Distillation)基本概念工作流程关键技术类型应用场景优势与挑战优势挑战 总结 2. 权重剪枝 (Model Pruning)基本原理二分类1. 非结构化剪枝&#xff08;Unstructur…

【单片机】ESP32-S3+多TMC2209控制步进电机系列1 UART通信及无传感回零 硬件部分

目录 1. 硬件选型1.1 esp32硬件型号1.2 TMC2209 硬件型号 2 原理接线图2.1 esp32接线2.2 TMC2209接线2.2.1 单向通讯 不配置地址2.2.2 单向通讯 配置地址2.2.3 双向通讯 单UART 【本文采用】2.2.4 双向通讯 多UART 3. 成品效果 1. 硬件选型 1.1 esp32硬件型号 采用的是微雪ES…

【论文复刻】雾霾污染及ZF治理与经济高质量发展(2004-2020年)

一、数据来源&#xff1a; PM2.5数据根据美国哥伦比亚大学社会经济数据与应用中心提供的全球PM2.5的年均浓度数据整理计算而得&#xff0c;人均实际GDP是以2000年为基期进行平减处理获得的实际GDP&#xff0c;控制变量来自《中国城市统计年鉴》、国家统计局&#xff0c;内含原…

行列式计算方法

行列式&#xff08;Determinant&#xff09;是线性代数中一个重要的概念&#xff0c;用来描述方阵的一些性质&#xff0c;尤其是与矩阵的可逆性、特征值等有关。下面是几种常见的计算行列式的方法&#xff1a; 1. 2x2矩阵的行列式 对于一个2x2矩阵&#xff1a; 行列式计算公式…

Elastic Cloud Serverless:深入探讨大规模自动扩展和性能压力测试

作者&#xff1a;来自 Elastic David Brimley, Jason Bryan, Gareth Ellis 及 Stewart Miles 深入了解 Elasticsearch Cloud Serverless 如何动态扩展以处理海量数据和复杂查询。我们探索其在实际条件下的性能&#xff0c;深入了解其可靠性、效率和可扩展性。 简介 Elastic Cl…

基于SpringBoot的旅游管理系统设计与实现

标题&#xff1a; 《基于SpringBoot的旅游管理系统设计与实现》 摘要&#xff1a; 本研究的主要目标是设计与实现基于Spring Boot的现代化旅游管理系统&#xff0c;旨在有效解决传统系统存在的多项问题&#xff0c;如用户体验不佳、功能不完善以及安全性方面的隐患。随着互联网…

LeetCode 热题100(十五)【动态规划】(3)

15.7最长递增子序列&#xff08;中等&#xff09; 题目描述&#xff1a;leetcode链接 300. 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元…

精华帖分享|书中自有黄金屋系列2——格雷厄姆估值因子

本文来源于量化小论坛股票量化板块精华帖&#xff0c;作者为Benlyn&#xff0c;发布于2024年2月2日。 以下为精华帖正文&#xff1a; 01 前言 巴菲特一直强调“以合理的估值买入好公司”的投资理念&#xff0c;因此今天想给大家介绍一下与估值相关的内容。买股票买好公司固然…

干部谈话考察系统如何实现灵活定制和精准考评?

在当今社会&#xff0c;干部选拔与任用已成为各类组织内部管理的关键环节。为了确保选拔出的干部具备高素质和卓越能力&#xff0c;干部谈话考察系统应运而生。这一系统以其灵活定制和精准考评的特点&#xff0c;为组织提供了科学、高效的干部考察手段。 干部谈话考察系统通过集…

云渲染特效广告一秒费用预估是多少?

在计算云渲染特效广告每秒钟的费用时&#xff0c;我们需要综合考虑多个关键因素&#xff0c;包括特效的复杂性、所需的渲染计算能力以及对渲染质量的具体要求。通常情况下&#xff0c;影视特效级别的广告因其场景极其复杂&#xff0c;每帧渲染所需时间较长&#xff0c;从而导致…