UIUtils.ts 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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 AnimBezierMoveAndTranslate(
  201. node: Node,
  202. targetPos: Vec3,
  203. scale: number,
  204. duration: number,
  205. callback?: Function
  206. ) {
  207. if (!isValid(node)) {
  208. return;
  209. }
  210. let opacityComp = node.getComponent(UIOpacity);
  211. if (!opacityComp) {
  212. opacityComp = node.addComponent(UIOpacity);
  213. }
  214. const startPos = node.getPosition();
  215. const startScale = node.scale.clone();
  216. const ctrl = new Vec3(
  217. (startPos.x + targetPos.x) / 2,
  218. Math.max(startPos.y, targetPos.y) + 150,
  219. (startPos.z + targetPos.z) / 2
  220. );
  221. const tempPos = new Vec3();
  222. const tempScale = new Vec3();
  223. tween({ t: 0 })
  224. .to(
  225. duration,
  226. { t: 1 },
  227. {
  228. easing: "quadInOut",
  229. onUpdate: (obj) => {
  230. if (!isValid(node)) {
  231. return;
  232. }
  233. const t = obj.t;
  234. const oneMinusT = 1 - t;
  235. // 贝塞尔曲线计算
  236. tempPos.x =
  237. oneMinusT * oneMinusT * startPos.x +
  238. 2 * t * oneMinusT * ctrl.x +
  239. t * t * targetPos.x;
  240. tempPos.y =
  241. oneMinusT * oneMinusT * startPos.y +
  242. 2 * t * oneMinusT * ctrl.y +
  243. t * t * targetPos.y;
  244. tempPos.z =
  245. oneMinusT * oneMinusT * startPos.z +
  246. 2 * t * oneMinusT * ctrl.z +
  247. t * t * targetPos.z;
  248. node.setPosition(tempPos);
  249. // 缩放插值计算
  250. tempScale.set(
  251. startScale.x + (scale - startScale.x) * t,
  252. startScale.y + (scale - startScale.y) * t,
  253. startScale.z + (scale - startScale.z) * t
  254. );
  255. node.setScale(tempScale);
  256. //设置透明度,越来越透明
  257. opacityComp.opacity = 255 * (1 - t);
  258. },
  259. }
  260. )
  261. .call(() => {
  262. if (callback) callback();
  263. })
  264. .start();
  265. }
  266. // 贝塞尔曲线实现移动和缩放动画
  267. static AnimBezierMoveAndScale(
  268. node: Node,
  269. targetPos: Vec3,
  270. scale: number,
  271. duration: number,
  272. callback?: Function,
  273. rotate?: number
  274. ) {
  275. if (!isValid(node)) {
  276. return;
  277. }
  278. const startPos = node.getPosition();
  279. const startScale = node.scale.clone();
  280. const ctrl = new Vec3(
  281. (startPos.x + targetPos.x) / 2,
  282. Math.max(startPos.y, targetPos.y) + 150,
  283. (startPos.z + targetPos.z) / 2
  284. );
  285. const tempPos = new Vec3();
  286. const tempScale = new Vec3();
  287. tween({ t: 0 })
  288. .to(
  289. duration,
  290. { t: 1 },
  291. {
  292. easing: "quadInOut",
  293. onUpdate: (obj) => {
  294. if (!isValid(node)) {
  295. return;
  296. }
  297. const t = obj.t;
  298. const oneMinusT = 1 - t;
  299. // 贝塞尔曲线计算
  300. tempPos.x =
  301. oneMinusT * oneMinusT * startPos.x +
  302. 2 * t * oneMinusT * ctrl.x +
  303. t * t * targetPos.x;
  304. tempPos.y =
  305. oneMinusT * oneMinusT * startPos.y +
  306. 2 * t * oneMinusT * ctrl.y +
  307. t * t * targetPos.y;
  308. tempPos.z =
  309. oneMinusT * oneMinusT * startPos.z +
  310. 2 * t * oneMinusT * ctrl.z +
  311. t * t * targetPos.z;
  312. node.setPosition(tempPos);
  313. // 缩放插值计算
  314. tempScale.set(
  315. startScale.x + (scale - startScale.x) * t,
  316. startScale.y + (scale - startScale.y) * t,
  317. startScale.z + (scale - startScale.z) * t
  318. );
  319. node.setScale(tempScale);
  320. if (rotate) {
  321. node.setRotationFromEuler(new Vec3(0, 0, rotate * t));
  322. }
  323. },
  324. }
  325. )
  326. .call(() => {
  327. if (callback) callback();
  328. })
  329. .start();
  330. }
  331. public static _findInChildren(node: Node, name: string): Node {
  332. var x = node.getChildByName(name);
  333. if (x) return x;
  334. if (node.children.length == 0) return null;
  335. for (var i = 0; i < node.children.length; ++i) {
  336. var tmp = this._findInChildren(node.children[i], name);
  337. if (tmp) return tmp;
  338. }
  339. return null;
  340. }
  341. public static async SetSprite(
  342. sprite: Sprite,
  343. filepath: string,
  344. cb: Function
  345. ) {
  346. return new Promise((resolve, reject) => {
  347. if (sprite) {
  348. AB.ins
  349. .loadRes(filepath + "/spriteFrame", SpriteFrame)
  350. .then((ret: SpriteFrame) => {
  351. if (isValid(sprite.node)) {
  352. sprite.spriteFrame = ret;
  353. resolve(null);
  354. cb();
  355. } else {
  356. }
  357. })
  358. .catch((e) => {
  359. console.log(filepath);
  360. console.log(e);
  361. });
  362. }
  363. });
  364. }
  365. }