ScrollBeta.ts 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. /**
  2. * @Author wutianhao
  3. * @ctime 2021-07-13
  4. * @Version
  5. * ScrollBeta1.0 2021-07-13 ScrollFinal改版 支持带标题的滚动列表 具体用法可参照天赋技能预览界面
  6. * @Tips
  7. * 复用滚动轴 用来减少drawcall
  8. * 与cc.ScrollView组件一同挂载在一个节点上
  9. * item挂载的脚本必须添加setData方法,用来传递数据
  10. * item锚点应该在中心
  11. * 目前Grid类型只支持从左上到右下模式(垂直滚动),其他奇葩模式自己搞定
  12. * 滚动轴的锚点必须放在滚动列表的起始位置(比如背包grid模式在左上角,成就列表在左上角)
  13. */
  14. import AssetMgr from "./AssetMgr";
  15. // 对象池类型
  16. let PoolEnum = cc.Enum({
  17. /**通用道具 */
  18. ITEM_BASE: 0,
  19. /**背包道具 */
  20. ITEM_BAG: 1,
  21. // /**合成道具 */
  22. // ITEM_COMPOSE: 2,
  23. })
  24. // 滚动类型
  25. let ScrollDirEnum = cc.Enum({
  26. /**垂直*/
  27. VERTICAL: 0,
  28. /**水平*/
  29. HORIZONTAL: 1,
  30. /**背包*/
  31. GRID: 2
  32. })
  33. type ItemList = { index: number, node: cc.Node }
  34. const { ccclass, property, menu } = cc._decorator;
  35. @ccclass
  36. @menu('Scroll/ScrollBeta')
  37. export default class ScrollBeta extends cc.Component {
  38. // @property(cc.ScrollView)
  39. // scroll: cc.ScrollView | null = null
  40. @property({
  41. tooltip: "使用对象池"
  42. })
  43. useNodePool: boolean = false
  44. @property({
  45. type: PoolEnum,
  46. visible: function () { return this.useNodePool },
  47. tooltip: "对象池类型"
  48. })
  49. private poolType = PoolEnum.ITEM_BASE
  50. @property({
  51. type: ScrollDirEnum,
  52. visible: () => {
  53. return true
  54. },
  55. tooltip: "滚动类型"
  56. })
  57. private scrollDir = ScrollDirEnum.VERTICAL // 滚动类型
  58. @property({ tooltip: "与滚动层的边界-左" })
  59. private padingX: number = 10
  60. @property({ tooltip: "与滚动层的边界-上" })
  61. private padingY: number = 10
  62. @property({ tooltip: "与滚动层的边界-下" })
  63. private padingY2: number = 0
  64. @property({
  65. visible: function () { return this.scrollDir != ScrollDirEnum.VERTICAL }, tooltip: "item行间距"
  66. })
  67. private spacingX: number = 20
  68. @property({
  69. visible: function () { return this.scrollDir != ScrollDirEnum.HORIZONTAL }, tooltip: "item列间距"
  70. })
  71. private spacingY: number = 20
  72. @property(cc.Prefab)
  73. itemPrefab: cc.Prefab = null // item资源加载地址
  74. @property(cc.Prefab)
  75. itemPrefabTitle: cc.Prefab = null // item标题资源加载地址
  76. @property
  77. itemScript: string = ""// item挂在的脚本名
  78. @property
  79. itemScriptTitle: string = ""// item标题挂在的脚本名
  80. @property
  81. itemScale: number = 1 // item缩放比例
  82. @property({
  83. tooltip: "是否开启滚动惯性"
  84. })
  85. inertia: boolean = true
  86. @property({
  87. tooltip: "开启惯性后,在用户停止触摸后滚动多块停止,0表示永不停止,1表示立即停止",
  88. visible: function () { return this.inertia == true },
  89. })
  90. brake: number = 0.75
  91. @property({
  92. tooltip: "是否允许滚动内容超过边界,并在停止触摸后回弹"
  93. })
  94. elastic: boolean = true
  95. @property({
  96. tooltip: "滚动行为是否会取消子节点上注册的触摸事件",
  97. })
  98. cancelInnerEvents: boolean = true
  99. @property({
  100. tooltip: "展示生产动画\n0->不展示\n1->缩放动画"
  101. })
  102. showAnim: number = 1
  103. @property({
  104. tooltip: "创建item的延迟时间,设为0则为每帧生成。\n注意:在所有item刷新完之前,scroll组件的滚动功能将被关闭"
  105. })
  106. ctime: number = 0
  107. @property({
  108. tooltip: "每帧生成item的个数"
  109. })
  110. cnumber: number = 1
  111. scrollView: cc.ScrollView
  112. mask: cc.Node
  113. content: cc.Node
  114. itemDataList: any[] = [] // 当前显示阵营的所有数据
  115. itemDataListMain: any[] = [] // 当前显示主数据的所有数据
  116. itemDataListTitle: any[] = [] // 当前显示标题的所有数据
  117. private extraParams: any[] = [] // 额外数据
  118. private itemListMain: ItemList[] = [] // 实例化的item列表
  119. private itemListTitle: ItemList[] = [] // 实例化的item标题列表
  120. private instantiateCount: number = 0 // item实例化数量
  121. private instantiateCountTitle: number = 0 // item标题实例化数量
  122. private hangCount: number = 0 // 行个数
  123. private lieCount: number = 0 // 列个数
  124. private itemDistanceX: number = 0 // item中心点之间的距离
  125. private itemDistanceXTitle: number = 0 // item标题中心点之间的距离
  126. private itemDistanceY: number = 0 // item中心点之间的距离
  127. private itemDistanceYTitle: number = 0 // item标题中心点之间的距离
  128. private scrollMaxOffsetX: number = 0 // 最大可滚动区域X
  129. private scrollMaxOffsetY: number = 0 // 最大可滚动区域Y
  130. private lastScrollPos: number = 0 //上一次的滚动位置
  131. private curScrollPos: number = 0 // 当前滚动位置
  132. private isScrollUp: boolean = false // 当前往哪个方向滚动 左和上是true
  133. private itemWidth: number = 10 // item宽度
  134. private itemWidthTitle: number = 10 // item标题宽度
  135. private itemHeight: number = 10 // item高度
  136. private itemHeightTitle: number = 10 // item标题高度
  137. private tagLang: number = 0
  138. private tagIndex: number = -999 // 999 表示清0状态,此时无【插入标签】,-1表示标签置顶,其他即当前标签的下方(右侧)显示
  139. private canCreateItem: boolean = false // 可以生成item
  140. private createIndex: number = 0 // 生成item的数据标签
  141. private life: number = 0 // 生成item的时间
  142. private baseIndex: number = 0 // 基础标签位置
  143. private hasInit: boolean = false
  144. offset: number = 0 // 偏移量
  145. onLoad() {
  146. if (this.node.getComponent(cc.ScrollView) != null) {
  147. console.error("滚动节点无需挂载scrollView组件了")
  148. return
  149. }
  150. /////////////// 构建滚动轴 ///////////////
  151. this.scrollView = this.addComponent(cc.ScrollView)
  152. this.scrollView.horizontal = this.scrollDir == ScrollDirEnum.HORIZONTAL
  153. this.scrollView.vertical = this.scrollDir != ScrollDirEnum.HORIZONTAL
  154. this.scrollView.inertia = this.inertia
  155. this.scrollView.brake = this.brake
  156. this.scrollView.elastic = this.elastic
  157. this.scrollView.cancelInnerEvents = this.cancelInnerEvents
  158. /////////////// 构建滚动遮罩 ///////////////
  159. this.mask = new cc.Node()
  160. this.mask.parent = this.node
  161. this.mask.setContentSize(this.node.getContentSize())
  162. this.mask.addComponent(cc.Mask)
  163. this.mask.getComponent(cc.Mask).type = cc.Mask.Type.RECT
  164. this.mask.anchorX = this.node.anchorX
  165. this.mask.anchorY = this.node.anchorY
  166. this.mask.x = 0
  167. this.mask.y = 0
  168. // widget不需要加了
  169. // let maskWidget = mask.addComponent(cc.Widget)
  170. // maskWidget.isAlignTop = true
  171. // maskWidget.isAlignBottom = true
  172. // maskWidget.isAlignLeft = true
  173. // maskWidget.isAlignRight = true
  174. // maskWidget.top = 0
  175. // maskWidget.bottom = 0
  176. // maskWidget.left = 0
  177. // maskWidget.right = 0
  178. /////////////// 构建滚动内容器 ///////////////
  179. this.content = new cc.Node()
  180. this.content.parent = this.mask
  181. this.scrollView.content = this.content
  182. this.content.setContentSize(this.node.getContentSize())
  183. this.content.anchorX = this.node.anchorX
  184. this.content.anchorY = this.node.anchorY
  185. this.content.x = 0
  186. this.content.y = 0
  187. }
  188. resetSize() {
  189. if (this.mask) {
  190. this.mask.setContentSize(this.node.getContentSize())
  191. }
  192. if (this.content) {
  193. this.content.setContentSize(this.node.getContentSize())
  194. }
  195. }
  196. private init() {
  197. if (this.hasInit) { return }
  198. this.hasInit = true
  199. this.itemWidth = this.itemPrefab.data.getContentSize().width
  200. this.itemHeight = this.itemPrefab.data.getContentSize().height
  201. this.itemWidthTitle = this.itemPrefabTitle.data.getContentSize().width
  202. this.itemHeightTitle = this.itemPrefabTitle.data.getContentSize().height
  203. this.itemDistanceX = this.realItemWidth + this.spacingX
  204. this.itemDistanceY = this.realItemHeight + this.spacingY
  205. this.itemDistanceXTitle = this.itemWidthTitle + this.spacingX
  206. this.itemDistanceYTitle = this.itemHeightTitle + this.spacingY
  207. this.scrollView.node.on('scrolling', this.onScroll, this)
  208. //看下有没有不应该有的组件
  209. // Layout
  210. if (this.scrollView.content.getComponent(cc.Layout)) {
  211. console.error("scrollFinal 与 layout 冲突,清删除 content 中的 layout 组件")
  212. }
  213. // Widget
  214. if (this.scrollView.node.getComponent(cc.Widget)) {
  215. if (this.scrollView.node.getComponent(cc.Widget).isAlignTop &&
  216. this.scrollView.node.getComponent(cc.Widget).isAlignBottom) {
  217. console.error("不能用widget做长度适配(因为Widget的延迟),只可用作坐标适配")
  218. }
  219. }
  220. }
  221. private setInstantCount() {
  222. if (this.scrollView == null) {
  223. return
  224. }
  225. switch (this.scrollDir) {
  226. case ScrollDirEnum.VERTICAL:
  227. this.hangCount = 1
  228. this.lieCount = Math.ceil(this.scrollView.node.height / (this.itemDistanceY)) + 1
  229. this.instantiateCount = this.lieCount
  230. break
  231. case ScrollDirEnum.HORIZONTAL:
  232. this.hangCount = Math.ceil(this.scrollView.node.width / (this.itemDistanceX)) + 1
  233. this.lieCount = 1
  234. this.instantiateCount = this.hangCount
  235. break
  236. case ScrollDirEnum.GRID:
  237. this.hangCount = Math.floor(this.scrollView.node.width / (this.itemDistanceX))
  238. this.lieCount = Math.ceil(this.scrollView.node.height / (this.itemDistanceY)) + 1
  239. this.instantiateCount = this.hangCount * this.lieCount
  240. break
  241. }
  242. this.instantiateCountTitle = this.itemDataListTitle.length
  243. }
  244. indexFrom: { [index: number]: number } = {}
  245. initScrollView(itemDataList: any[] = [], ...args: any[]) {
  246. // this.scheduleOnce(() => {
  247. this.init()
  248. this.clear()
  249. this.clearTag()
  250. this.itemDataList = itemDataList
  251. this.refreshData()
  252. this.extraParams = args
  253. this.scrollView.stopAutoScroll()
  254. this.setInstantCount()
  255. this.showUI()
  256. // }, 0)
  257. }
  258. refreshData() {
  259. this.itemDataListMain = []
  260. this.itemDataListTitle = []
  261. this.indexFrom = {}
  262. let count = 0
  263. this.itemDataList.forEach((element, index) => {
  264. element[0].forEach(_element => {
  265. this.itemDataListMain.push(_element)
  266. });
  267. this.itemDataListTitle.push(element[1])
  268. count += element[0].length
  269. this.indexFrom[index] = count
  270. });
  271. }
  272. private getPositionInView(item: cc.Node): { x: number, y: number } {
  273. if (this.scrollView == null) { return cc.v2(0, 0) }
  274. let worldPos = item.parent.convertToWorldSpaceAR(item.position);
  275. let viewPos = this.scrollView.node.convertToNodeSpaceAR(worldPos);
  276. return viewPos;
  277. }
  278. private onScroll() {
  279. this.curScrollPos = 0
  280. if (this.scrollDir == ScrollDirEnum.HORIZONTAL) {
  281. this.curScrollPos = this.scrollView.getScrollOffset().x
  282. this.isScrollUp = this.curScrollPos < this.lastScrollPos
  283. } else {
  284. this.curScrollPos = this.scrollView.getScrollOffset().y
  285. this.isScrollUp = this.curScrollPos > this.lastScrollPos
  286. }
  287. this.lastScrollPos = this.curScrollPos
  288. if (this.scrollView == null) { return }
  289. this.itemListMain.forEach(ele => {
  290. this.tryResetItem(ele)
  291. })
  292. // this.itemListTitle.forEach(ele => {
  293. // this.tryResetItemTitle(ele)
  294. // })
  295. }
  296. private tryResetItem(ele: ItemList) {
  297. switch (this.scrollDir) {
  298. case ScrollDirEnum.HORIZONTAL:
  299. if (this.curScrollPos >= 0 || this.curScrollPos <= this.scrollMaxOffsetX) {
  300. return
  301. }
  302. break
  303. case ScrollDirEnum.VERTICAL:
  304. case ScrollDirEnum.GRID:
  305. if (this.curScrollPos <= -this.realItemHeight / 2 || this.curScrollPos >= this.scrollMaxOffsetY + this.realItemHeight / 2) {
  306. return
  307. }
  308. }
  309. let scrollWidth = this.scrollView.node.width
  310. let scrollHeight = this.scrollView.node.height
  311. let element = ele.node
  312. switch (this.scrollDir) {
  313. case ScrollDirEnum.HORIZONTAL:
  314. if (this.isScrollUp && this.getPositionInView(element).x < -(this.itemDistanceX / 2)) {
  315. // 超出左边界显示区域
  316. let idx = ele.index + this.instantiateCount
  317. if (idx < this.itemDataListMain.length) {
  318. this.setItemData(element, this.itemDataListMain[idx], idx)
  319. // element.x = element.x + this.hangCount * this.itemDistanceX
  320. ele.index = idx
  321. this.setPosX(idx, element)
  322. }
  323. } else if (!this.isScrollUp && this.getPositionInView(element).x > (scrollWidth + this.itemDistanceX / 2)) {
  324. // 超出右边界显示区域
  325. let idx = ele.index - this.instantiateCount
  326. if (idx >= 0) {
  327. this.setItemData(element, this.itemDataListMain[idx], idx)
  328. // element.x = element.x - this.hangCount * this.itemDistanceX
  329. ele.index = idx
  330. this.setPosX(idx, element)
  331. }
  332. }
  333. break
  334. case ScrollDirEnum.VERTICAL:
  335. case ScrollDirEnum.GRID:
  336. if (this.isScrollUp && this.getPositionInView(element).y > this.itemDistanceY / 2) {
  337. // 超出上边界显示区域
  338. let idx = ele.index + this.instantiateCount
  339. if (idx < this.itemDataListMain.length && this.isScrollUp) {
  340. this.setItemData(element, this.itemDataListMain[idx], idx)
  341. ele.index = idx
  342. this.setPosX(idx, element)
  343. this.setPosY(idx, element)
  344. }
  345. } else if (!this.isScrollUp && this.curScrollPos > -this.itemDistanceY / 2 && this.getPositionInView(element).y < -(scrollHeight + this.itemDistanceY / 2)) {
  346. // 超出下边界显示区域
  347. let idx = ele.index - this.instantiateCount
  348. if (idx >= 0 && this.isScrollUp == false) {
  349. this.setItemData(element, this.itemDataListMain[idx], idx)
  350. ele.index = idx
  351. this.setPosX(idx, element)
  352. this.setPosY(idx, element)
  353. }
  354. }
  355. break
  356. }
  357. }
  358. private tryResetItemTitle(ele: ItemList) {
  359. switch (this.scrollDir) {
  360. case ScrollDirEnum.HORIZONTAL:
  361. if (this.curScrollPos >= 0 || this.curScrollPos <= this.scrollMaxOffsetX) {
  362. return
  363. }
  364. break
  365. case ScrollDirEnum.VERTICAL:
  366. case ScrollDirEnum.GRID:
  367. if (this.curScrollPos <= -this.itemHeightTitle / 2 || this.curScrollPos >= this.scrollMaxOffsetY + this.itemHeightTitle / 2) {
  368. return
  369. }
  370. }
  371. let scrollWidth = this.scrollView.node.width
  372. let scrollHeight = this.scrollView.node.height
  373. let element = ele.node
  374. switch (this.scrollDir) {
  375. case ScrollDirEnum.HORIZONTAL:
  376. if (this.isScrollUp && this.getPositionInView(element).x < -(this.itemDistanceXTitle / 2)) {
  377. // 超出左边界显示区域
  378. let idx = ele.index + this.instantiateCountTitle
  379. if (idx < this.itemDataListTitle.length) {
  380. this.addItemNodeTitle(idx, this.itemDataListTitle[idx])
  381. }
  382. } else if (!this.isScrollUp && this.getPositionInView(element).x > (scrollWidth + this.itemDistanceX / 2)) {
  383. // 超出右边界显示区域
  384. let idx = ele.index - this.instantiateCountTitle
  385. if (idx >= 0) {
  386. this.addItemNodeTitle(idx, this.itemDataListTitle[idx])
  387. }
  388. }
  389. break
  390. case ScrollDirEnum.VERTICAL:
  391. case ScrollDirEnum.GRID:
  392. if (this.isScrollUp && this.getPositionInView(element).y > this.itemDistanceYTitle / 2) {
  393. // 超出上边界显示区域
  394. let idx = ele.index + this.instantiateCountTitle
  395. if (idx < this.itemDataListTitle.length && this.isScrollUp) {
  396. this.addItemNodeTitle(idx, this.itemDataListTitle[idx])
  397. }
  398. } else if (!this.isScrollUp && this.curScrollPos > -this.itemDistanceYTitle / 2 && this.getPositionInView(element).y < -(scrollHeight + this.itemDistanceYTitle / 2)) {
  399. // 超出下边界显示区域
  400. let idx = ele.index - this.instantiateCountTitle
  401. if (idx >= 0 && this.isScrollUp == false) {
  402. this.addItemNodeTitle(idx, this.itemDataListTitle[idx])
  403. }
  404. }
  405. break
  406. }
  407. }
  408. checkIndexFromItem(index: number): number {
  409. let _index = 0
  410. for (let i = 0; i < index; i++) {
  411. const element = this.itemDataList[i][0]
  412. _index += element.length
  413. }
  414. return _index
  415. }
  416. checkIndexFromTitle(index: number): number {
  417. for (let i = 0; i < this.itemDataList.length; i++) {
  418. if (index < this.indexFrom[i]) {
  419. return i
  420. }
  421. }
  422. }
  423. checkAddTitle(index: number): boolean {
  424. let from = this.checkIndexFromTitle(index)
  425. if (from > 0) {
  426. return index == this.indexFrom[from - 1]
  427. } else {
  428. return index == 0
  429. }
  430. }
  431. private setPosX(index: number, node?: cc.Node): number {
  432. let x = 0
  433. switch (this.scrollDir) {
  434. case ScrollDirEnum.VERTICAL:
  435. x = this.scrollView.content.width / 2 + this.padingX//this.realItemWidth / 2 + this.padingX
  436. break
  437. case ScrollDirEnum.HORIZONTAL:
  438. x = index * this.itemDistanceX + this.realItemWidth / 2 + this.padingX + ((this.checkIndexFromTitle(index) + 1) * this.itemDistanceXTitle)
  439. if (this.tagIndex >= -1 && index > this.tagIndex) {
  440. x += this.tagLang
  441. }
  442. break
  443. case ScrollDirEnum.GRID:
  444. let _index = this.checkIndexFromTitle(index)
  445. let count = _index > 0 ? this.indexFrom[_index - 1] : 0
  446. x = (index - count) % this.hangCount * this.itemDistanceX + this.realItemWidth / 2 + this.padingX
  447. break
  448. }
  449. if (node) {
  450. node.x = x
  451. }
  452. return x
  453. }
  454. private setPosY(index: number, node?: cc.Node): number {
  455. let y = 0
  456. switch (this.scrollDir) {
  457. case ScrollDirEnum.VERTICAL:
  458. y = -index * this.itemDistanceY - this.realItemHeight / 2 - this.padingY -
  459. ((this.checkIndexFromTitle(index) + 1) * this.itemDistanceYTitle) + this.offset
  460. if (this.tagIndex >= -1 && index > this.tagIndex) {
  461. y -= this.tagLang
  462. }
  463. break
  464. case ScrollDirEnum.HORIZONTAL:
  465. y = -this.scrollView.content.height / 2 + this.padingY//-this.realItemHeight / 2 - this.padingY
  466. break
  467. case ScrollDirEnum.GRID:
  468. let _index = this.checkIndexFromTitle(index)
  469. let extra = 0
  470. if (_index > 0) {
  471. for (let i = 0; i < _index; i++) {
  472. extra += Math.ceil(this.itemDataList[i][0].length / this.hangCount)
  473. }
  474. }
  475. let count = _index > 0 ? this.indexFrom[_index - 1] : 0
  476. y = -(Math.floor((index - count) / this.hangCount) + extra) * this.itemDistanceY - this.realItemHeight / 2 - this.padingY -
  477. ((this.checkIndexFromTitle(index) + 1) * this.itemDistanceYTitle) + this.offset
  478. if (this.tagIndex >= -1 && (Math.floor((index - count) / this.hangCount) + extra) > this.tagIndex) {
  479. y -= this.tagLang
  480. }
  481. break
  482. }
  483. if (node) {
  484. node.y = y
  485. }
  486. return y
  487. }
  488. private setPosXTitle(index: number, node?: cc.Node): number {
  489. let x = 0
  490. switch (this.scrollDir) {
  491. case ScrollDirEnum.VERTICAL:
  492. x = this.scrollView.content.width / 2 + this.padingX//this.realItemWidth / 2 + this.padingX
  493. break
  494. case ScrollDirEnum.HORIZONTAL:
  495. x = this.checkIndexFromItem(index) * this.itemDistanceX + this.realItemWidth / 2 + this.padingX +
  496. ((index + 1) * this.itemDistanceXTitle) - this.realItemWidth / 2 - this.spacingX - this.itemWidthTitle / 2
  497. if (this.tagIndex >= -1 && index > this.tagIndex) {
  498. x += this.tagLang
  499. }
  500. break
  501. case ScrollDirEnum.GRID:
  502. x = this.scrollView.content.width / 2
  503. break
  504. }
  505. if (node) {
  506. node.x = x
  507. }
  508. return x
  509. }
  510. private setPosYTitle(index: number, node?: cc.Node): number {
  511. let y = 0
  512. switch (this.scrollDir) {
  513. case ScrollDirEnum.VERTICAL:
  514. y = -this.checkIndexFromItem(index) * this.itemDistanceY - this.realItemHeight / 2 - this.padingY -
  515. ((index + 1) * this.itemDistanceYTitle) + this.realItemHeight / 2 + this.spacingY + this.itemHeightTitle / 2
  516. break
  517. case ScrollDirEnum.HORIZONTAL:
  518. y = -this.scrollView.content.height / 2 + this.padingY//-this.realItemHeight / 2 - this.padingY
  519. break
  520. case ScrollDirEnum.GRID:
  521. let extra = 0
  522. if (index > 0) {
  523. for (let i = 0; i < index; i++) {
  524. extra += Math.ceil(this.itemDataList[i][0].length / this.hangCount)
  525. }
  526. }
  527. let count = index > 0 ? this.indexFrom[index - 1] : 0
  528. y = -(Math.floor((this.checkIndexFromItem(index) - count) / this.hangCount) + extra) * this.itemDistanceY - this.realItemHeight / 2 - this.padingY -
  529. ((index + 1) * this.itemDistanceYTitle) + this.realItemHeight / 2 + this.spacingY + this.itemHeightTitle / 2
  530. if (this.tagIndex >= -1 && (Math.floor((index - count) / this.hangCount) + extra) > this.tagIndex) {
  531. y -= this.tagLang
  532. }
  533. break
  534. }
  535. if (node) {
  536. node.y = y
  537. }
  538. return y
  539. }
  540. private setItemData(itemNode: cc.Node, data: any, index: number, isRefresh: boolean = false) {
  541. try {
  542. itemNode.getComponent(this.itemScript).setData(data, index, this.extraParams)
  543. if (isRefresh == false) {
  544. let addTitle = this.checkAddTitle(index)
  545. if (addTitle) {
  546. this.addItemNodeTitle(this.checkIndexFromTitle(index), this.itemDataListTitle[this.checkIndexFromTitle(index)])
  547. }
  548. }
  549. } catch (error) {
  550. console.error("脚本中缺少setData方法,或者方法报错", error)
  551. }
  552. }
  553. private setItemDataTitle(itemNode: cc.Node, data: any, index: number) {
  554. try {
  555. itemNode.getComponent(this.itemScriptTitle).setData(data, index, this.extraParams)
  556. } catch (error) {
  557. console.error("脚本中缺少setData方法,或者方法报错", error)
  558. }
  559. }
  560. // refreshItems调用,在刷新时可能需要重置item的index标签
  561. private resetIndex(index: number): number {
  562. if (this.itemDataListMain[index] != null) {
  563. return index
  564. }
  565. return this.resetIndex(index - this.instantiateCount)
  566. }
  567. // 刷新单独的item
  568. refreshItem(index: number, data) {
  569. if (this.itemDataListMain[index] == null) {
  570. return
  571. }
  572. this.itemDataListMain[index] = data
  573. if (this.getItem(index) == null) {
  574. return
  575. }
  576. this.setItemData(this.getItem(index), this.itemDataListMain[index], index)
  577. }
  578. // refreshItem(index: number) {
  579. // this.setItemData(this.getItem(index), this.itemDataListMain[index], index)
  580. // }
  581. refreshItems(itemDataList: any[], ...args: any[]) {
  582. this.itemDataList = itemDataList
  583. this.refreshData()
  584. if (args.length > 0) {
  585. this.extraParams = args
  586. }
  587. this.fixItemNodes()
  588. // 最终构造完整的 itemList 列表,刷新数据
  589. this.itemListMain.forEach(element => {
  590. try {
  591. let newIndex = this.resetIndex(element.index)
  592. element.index = newIndex
  593. this.setItemData(element.node, this.itemDataListMain[element.index], element.index)
  594. this.setPosX(element.index, element.node)
  595. this.setPosY(element.index, element.node)
  596. // element.node.getComponent(this.itemScript).setData(this.itemDataListMain[element.index], element.index, this.extraParams)
  597. } catch (error) {
  598. console.warn("脚本中缺少refreshItem方法,或者方法报错", error)
  599. }
  600. })
  601. }
  602. // 数据新增或减少时,增加或减少item
  603. fixItemNodes() {
  604. // 判断是否需要删除 itemList 里的数据
  605. if (this.itemDataListMain.length < this.instantiateCount && this.itemListMain.length > this.itemDataListMain.length) {
  606. let needDeleteCount = this.itemListMain.length - this.itemDataListMain.length
  607. for (let index = this.itemDataListMain.length; index < this.itemDataListMain.length + needDeleteCount; index++) {
  608. this.itemListMain[index].node.destroy()
  609. }
  610. this.itemListMain.splice(this.itemDataListMain.length, needDeleteCount)
  611. // 判断是否需要增加 itemList 里的数据
  612. } else if (this.itemListMain.length < this.instantiateCount && this.itemListMain.length < this.itemDataListMain.length) {
  613. let addCount = Math.min(this.instantiateCount - this.itemListMain.length, this.itemDataListMain.length - this.itemListMain.length)
  614. let startIndex = 0
  615. this.itemListMain.forEach(element => {
  616. startIndex = Math.max(element.index + 1, startIndex)
  617. });
  618. for (let addIndex = startIndex; addIndex < (startIndex + addCount); addIndex++) {
  619. this.addItemNode(addIndex, this.itemDataListMain[addIndex], true)
  620. }
  621. }
  622. // 判断是否需要删除 itemList 里的数据
  623. if (this.itemDataListTitle.length < this.instantiateCountTitle && this.itemListTitle.length > this.itemDataListTitle.length) {
  624. let needDeleteCount = this.itemListTitle.length - this.itemDataListTitle.length
  625. for (let index = this.itemDataListTitle.length; index < this.itemDataListTitle.length + needDeleteCount; index++) {
  626. this.itemListTitle[index].node.destroy()
  627. }
  628. this.itemListTitle.splice(this.itemDataListTitle.length, needDeleteCount)
  629. }
  630. this.instantiateCountTitle = this.itemDataListTitle.length
  631. if (this.content) {
  632. this.setScrollContentSize()
  633. }
  634. }
  635. private get realItemWidth(): number {
  636. return this.itemWidth * this.itemScale
  637. }
  638. private get realItemHeight(): number {
  639. return this.itemHeight * this.itemScale
  640. }
  641. private initItemNode(): cc.Node {
  642. return AssetMgr.instantiate(this.node, this.itemPrefab, false)
  643. // @TODO PoolManager
  644. // if (this.useNodePool) {
  645. // if (this.poolType == PoolEnum.ITEM_BAG) {
  646. // return PoolManager.getItemBag(this.itemPrefab)
  647. // } else if (this.poolType == PoolEnum.ITEM_BASE) {
  648. // return PoolManager.getItemBase(this.itemPrefab)
  649. // }
  650. // } else {
  651. // return cc.instantiate(this.itemPrefab)
  652. // }
  653. }
  654. private _initItemNode(): cc.Node {
  655. return AssetMgr.instantiate(this.node, this.itemPrefabTitle, false)
  656. // @TODO PoolManager
  657. // if (this.useNodePool) {
  658. // if (this.poolType == PoolEnum.ITEM_BAG) {
  659. // return PoolManager.getItemBag(this.itemPrefab)
  660. // } else if (this.poolType == PoolEnum.ITEM_BASE) {
  661. // return PoolManager.getItemBase(this.itemPrefab)
  662. // }
  663. // } else {
  664. // return cc.instantiate(this.itemPrefab)
  665. // }
  666. }
  667. private showUI() {
  668. if (this.itemPrefab == null || this.itemPrefabTitle == null) {
  669. console.error("item预制体加载失败")
  670. return
  671. }
  672. if (this.scrollView == null) {
  673. console.error("没有绑定scroll")
  674. return
  675. }
  676. this.setCreateItems(true)
  677. this.scrollView.content.setAnchorPoint(0, 1)
  678. this.scrollView.content.setPosition(-this.scrollView.node.width / 2, this.scrollView.node.height / 2)
  679. this.setScrollContentSize()
  680. switch (this.scrollDir) {
  681. case ScrollDirEnum.VERTICAL:
  682. this.scrollView.scrollToTop()
  683. break
  684. case ScrollDirEnum.HORIZONTAL:
  685. this.scrollView.scrollToLeft()
  686. break
  687. case ScrollDirEnum.GRID:
  688. this.scrollView.scrollToTop()
  689. break
  690. }
  691. }
  692. private setCreateItems(bool: boolean) {
  693. if (bool) {
  694. this.scrollView.enabled = false
  695. this.canCreateItem = true
  696. this.createIndex = 0
  697. this.baseIndex = 0
  698. this.life = 0
  699. // this._canCreateItem = true
  700. // this._createIndex = 0
  701. // this._life = 0
  702. } else {
  703. this.scrollView.enabled = true
  704. this.canCreateItem = false
  705. this.createIndex = 0
  706. this.baseIndex = 0
  707. this.life = 0
  708. // this._canCreateItem = false
  709. // this._createIndex = 0
  710. // this._life = 0
  711. }
  712. }
  713. update(dt: number) {
  714. if (!this.canCreateItem) {
  715. return
  716. }
  717. for (let index = 0; index < this.cnumber; index++) {
  718. this.updateForCreateItem(dt)
  719. }
  720. // if (!this._canCreateItem) {
  721. // return
  722. // }
  723. // for (let index = 0; index < this.cnumber; index++) {
  724. // this._updateForCreateItem(dt)
  725. // }
  726. }
  727. private updateForCreateItem(dt: number) {
  728. if (!this.canCreateItem) {
  729. return
  730. }
  731. if (this.life == 0) {
  732. // 生
  733. let _itemData = this.itemDataListMain[this.baseIndex]
  734. if (this.createIndex >= this.instantiateCount || _itemData == null) {
  735. this.setCreateItems(false)
  736. return
  737. }
  738. this.addItemNode(this.baseIndex, _itemData)
  739. this.createIndex += 1
  740. this.baseIndex += 1
  741. }
  742. this.life += dt
  743. if (this.life >= this.ctime) {
  744. this.life = 0
  745. }
  746. }
  747. private setScrollContentSize() {
  748. let val = 0
  749. switch (this.scrollDir) {
  750. case ScrollDirEnum.VERTICAL:
  751. for (let i = 0; i < this.itemDataList.length; i++) {
  752. val += this.itemDistanceYTitle
  753. for (let j = 0; j < this.itemDataList[i][0].length; j++) {
  754. val += this.itemDistanceY
  755. }
  756. }
  757. this.scrollView.content.setContentSize(this.scrollView.node.width, val + this.padingY + this.padingY2 + this.tagLang)
  758. break
  759. case ScrollDirEnum.HORIZONTAL:
  760. for (let i = 0; i < this.itemDataList.length; i++) {
  761. val += this.itemDistanceXTitle
  762. for (let j = 0; j < this.itemDataList[i][0].length; j++) {
  763. val += this.itemDistanceX
  764. }
  765. }
  766. this.scrollView.content.setContentSize(val + this.padingX + this.tagLang, this.scrollView.node.height)
  767. break
  768. case ScrollDirEnum.GRID:
  769. for (let i = 0; i < this.itemDataList.length; i++) {
  770. val += this.itemDistanceYTitle
  771. for (let j = 0; j < Math.ceil(this.itemDataList[i][0].length / this.hangCount); j++) {
  772. val += this.itemDistanceY
  773. }
  774. }
  775. this.scrollView.content.setContentSize(this.scrollView.node.width, val + this.padingY + this.padingY2 + this.tagLang)
  776. break
  777. }
  778. this.scrollMaxOffsetX = -this.scrollView.getMaxScrollOffset().x
  779. this.scrollMaxOffsetY = this.scrollView.getMaxScrollOffset().y
  780. }
  781. /**
  782. * 弹出详情标签,将会重设后续item的坐标。
  783. * @param index item标签
  784. * @param lang 坐标偏移量
  785. */
  786. setTag(index: number, lang: number) {
  787. this.tagLang = lang
  788. switch (this.scrollDir) {
  789. case ScrollDirEnum.VERTICAL:
  790. case ScrollDirEnum.HORIZONTAL:
  791. this.tagIndex = index
  792. break
  793. case ScrollDirEnum.GRID:
  794. this.tagIndex = Math.floor(index / this.hangCount)
  795. break
  796. }
  797. this.setScrollContentSize()
  798. this.itemListMain.forEach((element) => {
  799. this.setPosX(element.index, element.node)
  800. this.setPosY(element.index, element.node)
  801. });
  802. }
  803. /**清除详情标签,恢复item默认坐标 */
  804. clearTag() {
  805. this.setTag(-999, 0)
  806. // 修正index和坐标
  807. let scrollHeight = this.scrollView.node.height
  808. this.itemListMain.forEach(ele => {
  809. // 判断是否超出边界
  810. if (this.getPositionInView(ele.node).y > this.itemDistanceY / 2) {
  811. if (ele.index + this.instantiateCount < this.itemDataListMain.length) {
  812. ele.index += this.instantiateCount
  813. }
  814. this.setPosY(ele.index, ele.node)
  815. this.setItemData(ele.node, this.itemDataListMain[ele.index], ele.index)
  816. } else if (this.getPositionInView(ele.node).y < -(scrollHeight + this.itemDistanceY / 2)) {
  817. if (ele.index - this.instantiateCount >= 0) {
  818. ele.index -= this.instantiateCount
  819. }
  820. this.setPosY(ele.index, ele.node)
  821. this.setItemData(ele.node, this.itemDataListMain[ele.index], ele.index)
  822. }
  823. })
  824. this.setScrollContentSize()
  825. }
  826. /**删除某个元素 */
  827. del(index: number) {
  828. if (this.itemDataListMain.length < index) { return }
  829. this.itemDataListMain.splice(index, 1)
  830. // // 判断下是否需要删除节点
  831. if (this.itemListMain.length > this.itemDataListMain.length) {
  832. this.itemListMain.pop().node.destroy()
  833. }
  834. this.setScrollContentSize()
  835. for (let index = 0; index < this.itemListMain.length; index++) {
  836. let element = this.itemListMain[index]
  837. if (this.itemDataListMain[element.index] == null) {
  838. element.index -= this.instantiateCount
  839. break
  840. }
  841. }
  842. this.itemListMain.forEach((element) => {
  843. this.setPosX(element.index, element.node)
  844. this.setPosY(element.index, element.node)
  845. this.setItemData(element.node, this.itemDataListMain[element.index], element.index)
  846. });
  847. }
  848. /**在末尾添加一个元素 */
  849. add(data: any) {
  850. this.itemDataListMain.push(data)
  851. // 判断是否需要增加item
  852. if (this.itemListMain.length >= this.instantiateCount) {
  853. // 不需要
  854. // 判断下是否需要把最前面的放到最后面:1
  855. let needUpdate = false
  856. for (let index = 0; index < this.itemListMain.length; index++) {
  857. if (this.itemListMain[index].index == this.itemDataListMain.length - 2) {
  858. needUpdate = true
  859. break
  860. }
  861. }
  862. if (needUpdate) {
  863. let minIndex = 1000 //这个是最小值
  864. let minUpdateIndex = 0// 这个是最小值的标签
  865. for (let i = 0; i < this.itemListMain.length; i++) {
  866. if (this.itemListMain[i].index < minIndex) {
  867. minIndex = this.itemListMain[i].index
  868. minUpdateIndex = i
  869. }
  870. }
  871. // 判断下是否需要把最前面的放到最后面:2
  872. let _nodePos = 0
  873. let _offset = 0
  874. let needUpdate2 = false
  875. switch (this.scrollDir) {
  876. case ScrollDirEnum.HORIZONTAL:
  877. _nodePos = this.itemListMain[minUpdateIndex].node.x
  878. _offset = this.scrollView.getScrollOffset().x
  879. needUpdate2 = _nodePos + _offset > this.itemWidth / 2
  880. break
  881. case ScrollDirEnum.VERTICAL:
  882. case ScrollDirEnum.GRID:
  883. _nodePos = this.itemListMain[minUpdateIndex].node.y
  884. _offset = this.scrollView.getScrollOffset().y
  885. needUpdate2 = _nodePos + _offset > this.itemHeight / 2
  886. break
  887. }
  888. if (needUpdate2) {
  889. this.itemListMain[minUpdateIndex].index += this.instantiateCount
  890. this.setItemData(this.itemListMain[minUpdateIndex].node, data, this.itemListMain[minUpdateIndex].index)
  891. this.setPosX(this.itemListMain[minUpdateIndex].index, this.itemListMain[minUpdateIndex].node)
  892. this.setPosY(this.itemListMain[minUpdateIndex].index, this.itemListMain[minUpdateIndex].node)
  893. }
  894. }
  895. } else {
  896. // 需要
  897. let index = this.itemDataListMain.length - 1
  898. this.addItemNode(index, data)
  899. }
  900. this.setScrollContentSize()
  901. }
  902. private addItemNode(index: number, data: any, isRefresh: boolean = false) {
  903. let _node = this.initItemNode()
  904. this.scrollView.content.addChild(_node)
  905. this.setItemData(_node, data, index, isRefresh)
  906. this.itemListMain.push({ index: index, node: _node })
  907. this.setPosX(index, _node)
  908. this.setPosY(index, _node)
  909. if (isRefresh || this.showAnim == 0) {
  910. _node.scale = this.itemScale
  911. } else if (this.showAnim == 1) {
  912. _node.scale = 0
  913. cc.tween(_node).
  914. to(0.1, { scale: this.itemScale + 0.1 }).
  915. to(0.1, { scale: this.itemScale }).
  916. start()
  917. } else {
  918. _node.scale = this.itemScale
  919. }
  920. }
  921. private addItemNodeTitle(index: number, data: any) {
  922. if (this.itemListTitle.findIndex(n => n.index == index) == -1) {
  923. let _node = this._initItemNode()
  924. this.scrollView.content.addChild(_node)
  925. this.setItemDataTitle(_node, data, index)
  926. this.itemListTitle.push({ index: index, node: _node })
  927. _node.zIndex = -999
  928. this.setPosXTitle(index, _node)
  929. this.setPosYTitle(index, _node)
  930. } else {
  931. this.setItemDataTitle(this.itemListTitle[index].node, data, index)
  932. this.setPosXTitle(index, this.itemListTitle[index].node)
  933. this.setPosYTitle(index, this.itemListTitle[index].node)
  934. }
  935. }
  936. /**
  937. * @param val 立刻滚动到目标标签,目标标签将在顶部|左侧出现
  938. * @param type 滚到哪里的类型(1.居中 2.顶部|左侧 3.底部|右侧)
  939. */
  940. scrollToIndexNow(val: number, type: number = 1, ...args: any[]) {
  941. if (val >= this.itemDataListMain.length) {
  942. val = this.itemDataListMain.length - 1
  943. }
  944. if (val < 0) { return }
  945. this.scrollView.stopAutoScroll()
  946. this.baseIndex = val
  947. let scrollPosIndex = this.baseIndex
  948. if (this.itemDataListMain.length - this.baseIndex < this.instantiateCount) {
  949. this.baseIndex -= this.instantiateCount - (this.itemDataListMain.length - this.baseIndex)
  950. } else {
  951. if (type == 1) {
  952. this.baseIndex -= Math.ceil(this.instantiateCount / 2)
  953. } else if (type == 3) {
  954. this.baseIndex -= (this.lieCount - 1) * this.hangCount
  955. }
  956. }
  957. if (this.scrollDir == ScrollDirEnum.GRID) {
  958. this.baseIndex -= this.baseIndex % this.hangCount
  959. }
  960. this.baseIndex = Math.max(this.baseIndex, 0)
  961. // 从第几个标签开始显示
  962. switch (this.scrollDir) {
  963. case ScrollDirEnum.HORIZONTAL:
  964. let _x = -(this.setPosX(scrollPosIndex) - this.itemDistanceX / 2)
  965. // 判断是否超过边界
  966. if (_x < this.scrollMaxOffsetX) {
  967. scrollPosIndex = this.itemDataListMain.length - this.instantiateCount
  968. this.scrollView.content.x = this.scrollMaxOffsetX
  969. } else {
  970. if (type == 1) {
  971. this.scrollView.content.x = Math.min(-(this.setPosX(scrollPosIndex) - this.scrollView.node.width / 2), 0)
  972. if (-(this.setPosX(scrollPosIndex) - this.scrollView.node.width / 2) >= 0) {
  973. this.baseIndex = 0
  974. }
  975. } else if (type == 2) {
  976. this.scrollView.content.x = -(this.setPosX(scrollPosIndex) - this.itemDistanceX / 2)
  977. } else {
  978. scrollPosIndex++
  979. this.scrollView.content.x = Math.min(-(this.setPosX(scrollPosIndex) - this.scrollView.node.width - this.itemWidth / 2 - this.spacingY), 0)
  980. if (-(this.setPosX(scrollPosIndex) - this.scrollView.node.width - this.itemWidth / 2 - this.spacingY) >= 0) {
  981. this.baseIndex = 0
  982. }
  983. }
  984. }
  985. break
  986. case ScrollDirEnum.VERTICAL:
  987. case ScrollDirEnum.GRID:
  988. let _y = (Math.abs(this.setPosY(scrollPosIndex)) - this.itemDistanceY / 2)
  989. if (_y > this.scrollMaxOffsetY) {
  990. scrollPosIndex = this.itemDataListMain.length - this.instantiateCount
  991. this.scrollView.content.y = this.scrollMaxOffsetY
  992. } else {
  993. if (type == 1) {
  994. this.scrollView.content.y = Math.max(Math.abs(this.setPosY(scrollPosIndex)) - this.scrollView.node.height / 2, 0)
  995. if (Math.abs(this.setPosY(scrollPosIndex)) - this.scrollView.node.height / 2 <= 0) {
  996. this.baseIndex = 0
  997. }
  998. } else if (type == 2) {
  999. this.scrollView.content.y = Math.abs(this.setPosY(scrollPosIndex)) - this.itemDistanceY / 2
  1000. } else {
  1001. scrollPosIndex = this.scrollDir == ScrollDirEnum.VERTICAL ? (scrollPosIndex + 1) : scrollPosIndex + this.hangCount
  1002. this.scrollView.content.y = Math.max(Math.abs(this.setPosY(scrollPosIndex)) - this.scrollView.node.height - this.itemHeight / 2 - this.spacingY, 0)
  1003. if (Math.abs(this.setPosY(scrollPosIndex)) - this.scrollView.node.height - this.itemHeight / 2 - this.spacingY <= 0) {
  1004. this.baseIndex = 0
  1005. }
  1006. }
  1007. }
  1008. break
  1009. }
  1010. if (args.length > 0) {
  1011. this.extraParams = args
  1012. }
  1013. this.fixItemNodes()
  1014. // 如果content有子项目,则重制目标点位置
  1015. if (this.itemListMain.length > 0) {
  1016. for (let index = 0; index < this.itemListMain.length; index++) {
  1017. // let i = this.baseIndex + index
  1018. let elemnet = this.itemListMain[index]
  1019. elemnet.index = this.baseIndex + index
  1020. this.setPosX(elemnet.index, elemnet.node)
  1021. this.setPosY(elemnet.index, elemnet.node)
  1022. this.setItemData(elemnet.node, this.itemDataListMain[elemnet.index], elemnet.index)
  1023. }
  1024. }
  1025. }
  1026. /**
  1027. * 尝试滚动到滚动视图中心
  1028. * @param index 标签
  1029. * @param type 滚到哪里的类型(1.居中 2.顶部|左侧 3.底部|右侧)
  1030. * @param time
  1031. */
  1032. scrollToIndex(index: number, type: number = 1, time: number = 1, offset: number = 0) {
  1033. if (this.itemDataListMain[index] == null) {
  1034. console.error("不存在此标签")
  1035. return
  1036. }
  1037. switch (this.scrollDir) {
  1038. case ScrollDirEnum.HORIZONTAL:
  1039. if (type == 1) {
  1040. this.scrollView.scrollToOffset(cc.v2(this.setPosX(index) - this.scrollView.node.width / 2 + offset, this.scrollView.getScrollOffset().y), time)
  1041. } else if (type == 2) {
  1042. this.scrollView.scrollToOffset(cc.v2(this.setPosX(index) - this.itemDistanceX / 2 + offset, this.scrollView.getScrollOffset().y), time)
  1043. } else {
  1044. index++
  1045. this.scrollView.scrollToOffset(cc.v2(this.setPosX(index) - this.scrollView.node.width + offset, this.scrollView.getScrollOffset().y - this.itemWidth / 2 - this.spacingX), time)
  1046. }
  1047. break
  1048. case ScrollDirEnum.VERTICAL:
  1049. case ScrollDirEnum.GRID:
  1050. if (type == 1) {
  1051. this.scrollView.scrollToOffset(cc.v2(this.scrollView.getScrollOffset().x, Math.abs(this.setPosY(index)) - this.scrollView.node.height / 2 + offset), time)
  1052. } else if (type == 2) {
  1053. this.scrollView.scrollToOffset(cc.v2(this.scrollView.getScrollOffset().x, Math.abs(this.setPosY(index)) - this.itemDistanceY / 2 + offset), time)
  1054. } else {
  1055. index = this.scrollDir == ScrollDirEnum.VERTICAL ? (index + 1) : index + this.hangCount
  1056. this.scrollView.scrollToOffset(cc.v2(this.scrollView.getScrollOffset().x, Math.abs(this.setPosY(index)) - this.scrollView.node.height - this.itemHeight / 2 - this.spacingY + offset), time)
  1057. }
  1058. break
  1059. }
  1060. // this.scheduleOnce(() => {
  1061. // this.refreshItem(index)
  1062. // }, time)
  1063. }
  1064. getItem(index: number): cc.Node | null {
  1065. for (const key in this.itemListMain) {
  1066. if (this.itemListMain[key].index == index) {
  1067. return this.itemListMain[key].node
  1068. }
  1069. }
  1070. return
  1071. }
  1072. // 使用对象池时,在切换界面时必须使用这个方法,将所有对象放到池中
  1073. // @TODO PoolManager
  1074. clear() {
  1075. if (this.scrollView && this.scrollView.content) {
  1076. this.scrollView.content.removeAllChildren()
  1077. }
  1078. // if (this.useNodePool) {
  1079. // this.itemListMain.forEach(element => {
  1080. // if (this.poolType == PoolEnum.ITEM_BAG) {
  1081. // PoolManager.putItemBag(element.node)
  1082. // } else if (this.poolType == PoolEnum.ITEM_BASE) {
  1083. // PoolManager.putItemBase(element.node)
  1084. // }
  1085. // });
  1086. // } else {
  1087. // if (this.scrollView && this.scrollView.content) {
  1088. // this.scrollView.content.removeAllChildren()
  1089. // }
  1090. // }
  1091. this.itemDataList = []
  1092. this.itemListMain = []
  1093. this.itemListTitle = []
  1094. this.itemDataListMain = []
  1095. this.itemDataListTitle = []
  1096. this.indexFrom = {}
  1097. }
  1098. }