UIUtils.ts 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. import {
  2. _decorator,
  3. Animation,
  4. Button,
  5. Component,
  6. EditBox,
  7. editorExtrasTag,
  8. find,
  9. isValid,
  10. js,
  11. Label,
  12. Node,
  13. ProgressBar,
  14. Quat,
  15. Slider,
  16. sp,
  17. Sprite,
  18. SpriteFrame,
  19. tween,
  20. UIOpacity,
  21. UITransform,
  22. Vec3,
  23. } from "cc";
  24. import { ScrollView } from "cc";
  25. import { Prefab } from "cc";
  26. import { instantiate } from "cc";
  27. import BaseUI from "./BaseUI";
  28. export default class UIUtils {
  29. static destroyNodeDelay(new_prop: Node, arg1: number) {
  30. setTimeout(() => {
  31. if (isValid(new_prop)) {
  32. new_prop.destroy();
  33. }
  34. }, arg1);
  35. }
  36. // static async addEmptyNode(layout: Node) {
  37. // let p = await Utils.loadRes("v2/ui/items/EmptyNode", Prefab);
  38. // let emptyNode = instantiate(p as unknown as Prefab);
  39. // emptyNode.active = true;
  40. // emptyNode.name = "EmptyNode";
  41. // emptyNode.parent = layout;
  42. // }
  43. static removeEmptyNode(content: Node) {
  44. let emptyNode = content.getChildByName("EmptyNode");
  45. if (emptyNode) {
  46. emptyNode.destroy();
  47. }
  48. }
  49. static moveToNewParentAndAnim(parent: Node, animNode: Node, cb: Function) {
  50. UIUtils.moveToNewParent(parent, animNode);
  51. UIUtils.AnimBezierMoveAndScale(
  52. animNode,
  53. new Vec3(0, 0, 0),
  54. 0.2,
  55. 0.8,
  56. () => {
  57. cb();
  58. }
  59. );
  60. }
  61. static hideAnim(node: Node, arg1: () => void) {
  62. tween(node)
  63. .to(0.2, { scale: new Vec3(0, 0, 0) })
  64. .call(() => {
  65. node.active = false;
  66. node.setScale(new Vec3(1, 1, 1));
  67. arg1();
  68. })
  69. .start();
  70. }
  71. static closeUI(node: Node) {
  72. if (!isValid(node)) {
  73. return;
  74. }
  75. node.active = false;
  76. node.parent = null;
  77. node.destroy();
  78. }
  79. public static DeepFindChildByName(parentNode: Node, name: string): Node {
  80. if (!isValid(parentNode)) {
  81. return null;
  82. }
  83. return UIUtils._findInChildren(parentNode, name);
  84. }
  85. // 将一个node节点移动到新的父节点
  86. static moveToNewParent(parent: Node, child: Node) {
  87. // 先转换child的世界坐标位置
  88. let cp = child.getWorldPosition(new Vec3());
  89. // 更换父节点
  90. child.setParent(parent, false);
  91. // 转换世界坐标到新父节点的本地坐标系
  92. const parentUITrans = parent.getComponent(UITransform);
  93. // 设置新的本地坐标,使其屏幕位置不变
  94. const newP = parentUITrans.convertToNodeSpaceAR(cp);
  95. child.setPosition(newP);
  96. }
  97. static AnimateLayoutItems(
  98. layout: Node,
  99. offsetX: number = -20,
  100. offsetY: number = -20,
  101. delayInterval: number = 0.1,
  102. duration: number = 0.3
  103. ): void {
  104. const children = layout.children;
  105. children.forEach((child, index) => {
  106. // 记录原始位置并设置初始偏移位置
  107. const originalPos = child.position.clone();
  108. child.setPosition(
  109. originalPos.x + offsetX,
  110. originalPos.y + offsetY,
  111. originalPos.z
  112. );
  113. // 设置透明度组件
  114. let opacityComp = child.getComponent(UIOpacity);
  115. if (!opacityComp) {
  116. opacityComp = child.addComponent(UIOpacity);
  117. }
  118. opacityComp.opacity = 0;
  119. // 启动动画
  120. tween(child)
  121. .delay(index * delayInterval)
  122. .parallel(
  123. tween(child).to(
  124. duration,
  125. { position: originalPos },
  126. { easing: "sineOut" }
  127. ),
  128. tween(opacityComp).to(duration, { opacity: 255 })
  129. )
  130. .start();
  131. });
  132. }
  133. static AnimScaleShake(
  134. node: Node,
  135. scale: number = 1.2,
  136. duration: number = 0.6,
  137. repeatForever: boolean = true,
  138. callback?: () => void
  139. ) {
  140. const originalScale = node.getScale().clone();
  141. const scaleUp = Vec3.multiplyScalar(new Vec3(), originalScale, scale);
  142. const animation = tween(node)
  143. .to(
  144. duration / 2,
  145. { scale: originalScale.clone().multiplyScalar(scale) },
  146. { easing: "quadOut" }
  147. )
  148. .to(duration / 2, { scale: originalScale }, { easing: "quadIn" });
  149. if (repeatForever) {
  150. animation.repeatForever().start();
  151. } else {
  152. animation
  153. .call(() => {
  154. if (callback) callback();
  155. })
  156. .start();
  157. }
  158. }
  159. static async AnimShakeUpAndDownByTimes(node: Node, duration: number) {
  160. // 根据动画的次数,计算出动画的间隔时间
  161. return new Promise((resolve, reject) => {
  162. tween(node)
  163. .to(
  164. duration / 2,
  165. { position: new Vec3(0, 30, 0) },
  166. { easing: "quadOut" }
  167. )
  168. .to(
  169. duration / 2,
  170. { position: new Vec3(0, 150, 0) },
  171. { easing: "quadIn" }
  172. )
  173. .call(() => {
  174. resolve(node);
  175. })
  176. .start();
  177. });
  178. }
  179. static async AsyncBezierMoveAndScale(
  180. node: Node,
  181. targetPos: Vec3,
  182. scale: number,
  183. duration: number,
  184. rotate?: number
  185. ) {
  186. return new Promise((resolve, reject) => {
  187. this.AnimBezierMoveAndScale(
  188. node,
  189. targetPos,
  190. scale,
  191. duration,
  192. () => {
  193. resolve(node);
  194. },
  195. rotate
  196. );
  197. });
  198. }
  199. static fadeIn(child: Node, duration: number) {
  200. if (!isValid(child)) {
  201. return;
  202. }
  203. let opacityComp = child.getComponent(UIOpacity);
  204. if (!opacityComp) {
  205. opacityComp = child.addComponent(UIOpacity);
  206. }
  207. child.setScale(0, 0);
  208. tween({ t: 0 })
  209. .to(
  210. duration,
  211. { t: 1 },
  212. {
  213. easing: "quadInOut",
  214. onUpdate: (obj) => {
  215. if (!isValid(child)) {
  216. return;
  217. }
  218. child.setScale(1 * obj.t, 1 * obj.t);
  219. opacityComp.opacity = 255 * obj.t;
  220. },
  221. }
  222. )
  223. .start();
  224. }
  225. static AnimBezierMoveAndTranslate(
  226. node: Node,
  227. targetPos: Vec3,
  228. scale: number,
  229. duration: number,
  230. callback?: Function
  231. ) {
  232. if (!isValid(node)) {
  233. return;
  234. }
  235. let opacityComp = node.getComponent(UIOpacity);
  236. if (!opacityComp) {
  237. opacityComp = node.addComponent(UIOpacity);
  238. }
  239. const startPos = node.getPosition();
  240. const startScale = node.scale.clone();
  241. const ctrl = new Vec3(
  242. (startPos.x + targetPos.x) / 2,
  243. Math.max(startPos.y, targetPos.y) + 150,
  244. (startPos.z + targetPos.z) / 2
  245. );
  246. const tempPos = new Vec3();
  247. const tempScale = new Vec3();
  248. tween({ t: 0 })
  249. .to(
  250. duration,
  251. { t: 1 },
  252. {
  253. easing: "quadInOut",
  254. onUpdate: (obj) => {
  255. if (!isValid(node)) {
  256. return;
  257. }
  258. const t = obj.t;
  259. const oneMinusT = 1 - t;
  260. // 贝塞尔曲线计算
  261. tempPos.x =
  262. oneMinusT * oneMinusT * startPos.x +
  263. 2 * t * oneMinusT * ctrl.x +
  264. t * t * targetPos.x;
  265. tempPos.y =
  266. oneMinusT * oneMinusT * startPos.y +
  267. 2 * t * oneMinusT * ctrl.y +
  268. t * t * targetPos.y;
  269. tempPos.z =
  270. oneMinusT * oneMinusT * startPos.z +
  271. 2 * t * oneMinusT * ctrl.z +
  272. t * t * targetPos.z;
  273. node.setPosition(tempPos);
  274. // 缩放插值计算
  275. tempScale.set(
  276. startScale.x + (scale - startScale.x) * t,
  277. startScale.y + (scale - startScale.y) * t,
  278. startScale.z + (scale - startScale.z) * t
  279. );
  280. node.setScale(tempScale);
  281. //设置透明度,越来越透明
  282. opacityComp.opacity = 255 * (1 - t);
  283. },
  284. }
  285. )
  286. .call(() => {
  287. if (callback) callback();
  288. })
  289. .start();
  290. }
  291. // 贝塞尔曲线实现移动和缩放动画
  292. static AnimBezierMoveAndScale(
  293. node: Node,
  294. targetPos: Vec3,
  295. scale: number,
  296. duration: number,
  297. callback?: Function,
  298. rotate?: number
  299. ) {
  300. if (!isValid(node)) {
  301. return;
  302. }
  303. const startPos = node.getPosition();
  304. const startScale = node.scale.clone();
  305. const ctrl = new Vec3(
  306. (startPos.x + targetPos.x) / 2,
  307. Math.max(startPos.y, targetPos.y) + 150,
  308. (startPos.z + targetPos.z) / 2
  309. );
  310. const tempPos = new Vec3();
  311. const tempScale = new Vec3();
  312. tween({ t: 0 })
  313. .to(
  314. duration,
  315. { t: 1 },
  316. {
  317. easing: "quadInOut",
  318. onUpdate: (obj) => {
  319. if (!isValid(node)) {
  320. return;
  321. }
  322. const t = obj.t;
  323. const oneMinusT = 1 - t;
  324. // 贝塞尔曲线计算
  325. tempPos.x =
  326. oneMinusT * oneMinusT * startPos.x +
  327. 2 * t * oneMinusT * ctrl.x +
  328. t * t * targetPos.x;
  329. tempPos.y =
  330. oneMinusT * oneMinusT * startPos.y +
  331. 2 * t * oneMinusT * ctrl.y +
  332. t * t * targetPos.y;
  333. tempPos.z =
  334. oneMinusT * oneMinusT * startPos.z +
  335. 2 * t * oneMinusT * ctrl.z +
  336. t * t * targetPos.z;
  337. node.setPosition(tempPos);
  338. // 缩放插值计算
  339. tempScale.set(
  340. startScale.x + (scale - startScale.x) * t,
  341. startScale.y + (scale - startScale.y) * t,
  342. startScale.z + (scale - startScale.z) * t
  343. );
  344. node.setScale(tempScale);
  345. if (rotate) {
  346. node.setRotationFromEuler(new Vec3(0, 0, rotate * t));
  347. }
  348. },
  349. }
  350. )
  351. .call(() => {
  352. if (callback) callback();
  353. })
  354. .start();
  355. }
  356. public static _findInChildren(node: Node, name: string): Node {
  357. var x = node.getChildByName(name);
  358. if (x) return x;
  359. if (node.children.length == 0) return null;
  360. for (var i = 0; i < node.children.length; ++i) {
  361. var tmp = this._findInChildren(node.children[i], name);
  362. if (tmp) return tmp;
  363. }
  364. return null;
  365. }
  366. }