UIUtils.ts 10 KB

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