源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
17 KiB

  1. LoopScrowViewMgr = LoopScrowViewMgr or BaseClass()
  2. local LoopScrowViewMgr = LoopScrowViewMgr
  3. function LoopScrowViewMgr:__init()
  4. self.item_width = 100 --item 宽度
  5. self.item_height = 100 --item 高度
  6. self.cull_content = true --是否隐藏 滑动列表之外的物体
  7. self.min_index = 0
  8. self.max_index = 0
  9. self.onInitializeItem = nil --更新item的委托
  10. self.max_per_line = 1 --每一行有多少列
  11. self.mTrans = nil --当前挂载这个组件的物体
  12. self.mPanel = nil -- scrowView 物体
  13. self.mScroll = nil -- scrowView 组件
  14. self.mHorizontal = false --是否是水平
  15. self.force_reset = true --强制复位
  16. self.item_list = {}
  17. self.mCachedScrowView = false
  18. self.mOriginalPosition = Vector3.zero
  19. self.mNeedToWrap = false
  20. self.mPanelDelta = Vector2.zero
  21. self.show_count = 0
  22. self.item_num = 0
  23. self.offset = 0
  24. self.start_pos = {x=0, y=0}
  25. self.corners = {}
  26. self.wrap_content_cb = false
  27. end
  28. function LoopScrowViewMgr:Init(mPanel,mTrans,max_per_line,item_width,item_height,onInitializeItem,offset, offset_y, start_pos, wrap_content_cb)
  29. self.mPanel = mPanel
  30. if self.mPanel.transform.pivot.x ~= 0.5 or self.mPanel.transform.pivot.y ~= 0.5 then
  31. -- 不要搞事情,计算的时候锚点不对会有计算错误请在预制就设置好scrollView的锚点
  32. -- self.mPanel.transform.pivot = Vector2(0.5,0.5)
  33. local size = self.mPanel.rect.size
  34. local mPanel_x = GetLocalPositionX(self.mPanel.transform)
  35. local mPanel_y = GetLocalPositionY(self.mPanel.transform)
  36. if self.mPanel.transform.pivot.x == 0 and self.mPanel.transform.pivot.y == 1 then
  37. self.mPanel.transform.localPosition = Vector3(mPanel_x + size.x/2, mPanel_y - size.y/2, 0)
  38. elseif self.mPanel.transform.pivot.x == 1 and self.mPanel.transform.pivot.y == 0 then
  39. self.mPanel.transform.localPosition = Vector3(mPanel_x - size.x/2, mPanel_y + size.y/2, 0)
  40. end
  41. self.mPanel.transform.pivot = Vector2(0.5,0.5)
  42. end
  43. self.mTrans = mTrans
  44. self.item_width = item_width
  45. self.item_height = item_height
  46. self.max_per_line = max_per_line or 1
  47. self.onInitializeItem = onInitializeItem
  48. self.offset = offset or 0
  49. self.start_pos = start_pos or {x=0, y=0}
  50. self.wrap_content_cb = wrap_content_cb or false
  51. self:CachedScrowView()
  52. end
  53. function LoopScrowViewMgr:__delete()
  54. if self.mScroll then
  55. self.mScroll.onValueChanged:RemoveAllListeners()
  56. end
  57. self.item_list = {}
  58. self.onInitializeItem = nil --更新item的委托
  59. self.mTrans = nil --当前挂载这个组件的物体
  60. self.mPanel = nil -- scrowView 物体
  61. self.mScroll = nil -- scrowView 组件
  62. end
  63. function LoopScrowViewMgr:ClearItemList()
  64. if self.item_list then
  65. for i,v in ipairs(self.item_list) do
  66. v:SetVisible(false, true)
  67. end
  68. self.max_index = 0
  69. end
  70. end
  71. function LoopScrowViewMgr:SetContentSizeData()
  72. if self.mHorizontal then
  73. if self.mTrans then
  74. self.mTrans.sizeDelta = Vector2(math.ceil(self.show_count/self.max_per_line) * self.item_width,self.max_per_line * self.item_height)
  75. end
  76. else
  77. if self.mTrans then
  78. self.mTrans.sizeDelta = Vector2(self.max_per_line * self.item_width,math.ceil(self.show_count/self.max_per_line) * self.item_height)
  79. end
  80. end
  81. end
  82. function LoopScrowViewMgr:CachedScrowView()
  83. if self.mCachedScrowView then
  84. if self.mScroll == nil then
  85. return
  86. end
  87. return self.mScroll and self.mScroll.horizontal or self.mScroll.vertical
  88. end
  89. self.mCachedScrowView = true
  90. if self.mPanel == nil then return false end
  91. if self.mTrans == nil then return false end
  92. self.mPanelDelta = self.mPanel.rect.size
  93. self.mOriginalPosition = self.mTrans.localPosition
  94. self.mScroll = self.mPanel.gameObject:GetComponent("ScrollRect")
  95. if self.mScroll == nil then return false end
  96. if self.mScroll.horizontal then
  97. self.mHorizontal = true
  98. elseif self.mScroll.vertical then
  99. self.mHorizontal = false
  100. else
  101. return false
  102. end
  103. return true
  104. end
  105. function LoopScrowViewMgr:InitChildren(item_list,show_count)
  106. self.show_count = show_count
  107. if not self:CachedScrowView() then
  108. return
  109. end
  110. if item_list then
  111. local len = TableSize(item_list)
  112. self.min_index = 1
  113. self.max_index = show_count
  114. self.mNeedToWrap = show_count > len
  115. self.item_list = {}
  116. if show_count < 0 or show_count > len then
  117. show_count = len
  118. end
  119. local item
  120. for i = 1,len do
  121. item = item_list[i]
  122. if show_count > 0 and item then
  123. item:SetVisible(true, true)
  124. table.insert(self.item_list,item)
  125. show_count = show_count - 1
  126. elseif item then
  127. table.insert(self.item_list,item)
  128. item:SetVisible(false, true)
  129. end
  130. end
  131. --是真实的item个数
  132. self.item_num = #self.item_list
  133. else
  134. self.item_num = 0
  135. end
  136. end
  137. function LoopScrowViewMgr:ResetScrowViewPanel(is_not_reset_pos)
  138. local is_not_reset_pos = is_not_reset_pos
  139. if self.mScroll then
  140. self.mScroll.onValueChanged:RemoveAllListeners()
  141. self:ResetPosition(is_not_reset_pos)
  142. self.mScroll.onValueChanged:AddListener(function()
  143. self:WrapContent()
  144. end)
  145. end
  146. end
  147. function LoopScrowViewMgr:ResetPosition(is_not_reset_pos)
  148. if not is_not_reset_pos then
  149. self.mTrans.localPosition = self.mOriginalPosition
  150. end
  151. end
  152. function LoopScrowViewMgr:ResetItemListPosition()
  153. local len = self.item_num
  154. for i = 1,len do
  155. local item = self.item_list[i]
  156. -- item:SetGameObjectName(tostring(i))
  157. if self.mHorizontal then
  158. local pos = self.max_per_line > 0 and
  159. Vector3(math.floor((i - 1) / self.max_per_line) * self.item_width + self.offset,- (math.floor(i - 1) % self.max_per_line * self.item_height), 0) or
  160. Vector3(-(i-1) * self.item_width,0,0)
  161. item:SetPosition(pos.x +self.start_pos.x, pos.y + self.start_pos.y)
  162. else
  163. local pos = self.max_per_line > 0 and
  164. Vector3(math.floor(i - 1) % self.max_per_line * self.item_width ,- math.floor((i - 1) / self.max_per_line) * self.item_height,0) or
  165. Vector3(0,-(i-1) * self.item_height,0)
  166. item:SetPosition(pos.x +self.start_pos.x, pos.y + self.start_pos.y)
  167. end
  168. end
  169. end
  170. function LoopScrowViewMgr:RestToBeginning(is_not_reset_pos)--is_not_reset_pos为true则不重置scroll位置
  171. if not self:CachedScrowView() then
  172. return
  173. end
  174. self:ResetScrowViewPanel(is_not_reset_pos)
  175. self:ResetItemListPosition()
  176. self.force_reset = true
  177. self:WrapContent()
  178. self.force_reset = false
  179. end
  180. --强制更新所有item数据
  181. function LoopScrowViewMgr:ForceUpdateCurrentItems()
  182. -- self.force_reset = true
  183. -- self:WrapContent()
  184. -- self.force_reset = false
  185. if self.mNeedToWrap and self.mTrans then
  186. self.corners = self:GetWorldCorners()
  187. for i = 1,4 do
  188. local v = self.corners[i]
  189. v = self.mTrans:InverseTransformPoint(v)
  190. self.corners[i] = v
  191. end
  192. end
  193. self:ForceUpdatePos(self.corners)
  194. end
  195. function LoopScrowViewMgr:ForceUpdatePos(corners)
  196. if corners == nil or #corners < 1 then return end
  197. if self.mHorizontal then
  198. local extents = self.max_per_line > 0 and (self.item_width * math.floor(self.item_num / self.max_per_line)) or self.item_width * self.item_num
  199. local halfExtents = extents*0.5
  200. local center = (corners[1] + corners[3]) * 0.5
  201. for i = 1,self.item_num do
  202. local item = self.item_list[i]
  203. local distance = item:GetPosition().x + self.item_width/2 - center.x
  204. local realIndex = self:GetRealIndex(item:GetPosition())
  205. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  206. -- item:SetGameObjectName(tostring(realIndex))
  207. if self.max_index > #self.item_list then
  208. item:SetVisible(true, true)
  209. end
  210. self:UpdateItem(item,i,realIndex)
  211. else
  212. item:SetVisible(false, true)
  213. end
  214. if extents > self.mPanelDelta.x then
  215. if math.abs(distance) > halfExtents then
  216. local pos = DeepCopy(item:GetPosition())
  217. pos.x = distance < 0 and pos.x + extents or pos.x - extents
  218. local realIndex = self:GetRealIndex(pos)
  219. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  220. item:SetPosition(pos.x, pos.y)
  221. -- item:SetGameObjectName(tostring(realIndex))
  222. if self.max_index > #self.item_list then
  223. item:SetVisible(true, true)
  224. end
  225. self:UpdateItem(item,i,realIndex)
  226. end
  227. end
  228. end
  229. end
  230. else
  231. local extents = self.max_per_line > 0 and (self.item_height * math.floor(self.item_num / self.max_per_line)) or self.item_height * self.item_num
  232. local halfExtents = extents*0.5
  233. local center = (corners[1] + corners[3]) * 0.5
  234. for i = 1,self.item_num do
  235. local item = self.item_list[i]
  236. local distance = item:GetPosition().y - self.item_height/2 - center.y
  237. local realIndex = self:GetRealIndex(item:GetPosition())
  238. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  239. -- item:SetGameObjectName(tostring(realIndex))
  240. if self.max_index > #self.item_list then
  241. item:SetVisible(true, true)
  242. end
  243. self:UpdateItem(item,i,realIndex)
  244. else
  245. item:SetVisible(false, true)
  246. end
  247. if extents > self.mPanelDelta.y then
  248. if math.abs(distance) > halfExtents then
  249. local pos = DeepCopy(item:GetPosition())
  250. pos.y = distance < 0 and pos.y + extents or pos.y - extents
  251. local realIndex = self:GetRealIndex(pos)
  252. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  253. item:SetPosition(pos.x, pos.y)
  254. -- item:SetGameObjectName(tostring(realIndex))
  255. if self.max_index > #self.item_list then
  256. item:SetVisible(true, true)
  257. end
  258. self:UpdateItem(item,i,realIndex)
  259. end
  260. end
  261. end
  262. end
  263. end
  264. end
  265. function LoopScrowViewMgr:GetWorldCorners()
  266. local mCorners = {}
  267. local x0 = -0.5 * self.mPanelDelta.x
  268. local y0 = -0.5 * self.mPanelDelta.y
  269. local x1 = x0 + self.mPanelDelta.x
  270. local y1 = y0 + self.mPanelDelta.y
  271. mCorners[1] = self.mPanel:TransformPoint(x0,y0,0)
  272. mCorners[2] = self.mPanel:TransformPoint(x0,y1,0)
  273. mCorners[3] = self.mPanel:TransformPoint(x1,y1,0)
  274. mCorners[4] = self.mPanel:TransformPoint(x1,y0,0)
  275. return mCorners
  276. end
  277. function LoopScrowViewMgr:WrapContent()
  278. if not self:CachedScrowView() then
  279. return
  280. end
  281. if self.mNeedToWrap or self.force_reset then
  282. self.corners = self:GetWorldCorners()
  283. for i = 1,4 do
  284. local v = self.corners[i]
  285. v = self.mTrans:InverseTransformPoint(v)
  286. self.corners[i] = v
  287. end
  288. if self.mHorizontal then
  289. self:WrapHorizontal(self.corners)
  290. else
  291. self:WrapVertical(self.corners)
  292. end
  293. end
  294. if self.wrap_content_cb then
  295. self.wrap_content_cb()
  296. end
  297. end
  298. function LoopScrowViewMgr:GetRealIndex(pos)
  299. if self.mHorizontal then
  300. return self.max_per_line > 0 and
  301. --这里一定要四舍五入,因为 位置会出现 原本 是 440,unity 可能会变成439.333
  302. round((pos.x - self.offset) / self.item_width) * self.max_per_line + round(-pos.y / self.item_height) + 1 or
  303. round(pos.x / self.item_width)
  304. else
  305. return self.max_per_line > 0 and
  306. --这里一定要四舍五入,因为 位置会出现 原本 是 440,unity 可能会变成439.333
  307. round(- pos.y / self.item_height) * self.max_per_line + round(pos.x / self.item_width) + 1 or
  308. round(- pos.y / self.item_height)
  309. end
  310. end
  311. function LoopScrowViewMgr:WrapVertical(corners)
  312. local extents = self.max_per_line > 1 and (self.item_height * math.floor(self.item_num / self.max_per_line)) or self.item_height * self.item_num
  313. local halfExtents = extents*0.5
  314. local center = (corners[1] + corners[3]) * 0.5
  315. for i = 1,self.item_num do
  316. local item = self.item_list[i]
  317. local distance = item:GetPosition().y - self.item_height/2 - center.y
  318. if self.force_reset then
  319. local realIndex = self:GetRealIndex(item:GetPosition())
  320. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  321. -- item:SetGameObjectName(tostring(realIndex))
  322. if self.max_index > #self.item_list then
  323. item:SetVisible(true, true)
  324. end
  325. self:UpdateItem(item,i,realIndex)
  326. end
  327. elseif extents > self.mPanelDelta.y then
  328. if math.abs(distance) > halfExtents then
  329. local pos = DeepCopy(item:GetPosition())
  330. pos.y = distance < 0 and pos.y + extents or pos.y - extents
  331. local realIndex = self:GetRealIndex(pos)
  332. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  333. item:SetPosition(pos.x, pos.y)
  334. -- item:SetGameObjectName(tostring(realIndex))
  335. if self.max_index > #self.item_list then
  336. item:SetVisible(true, true)
  337. end
  338. self:UpdateItem(item,i,realIndex)
  339. end
  340. end
  341. end
  342. end
  343. end
  344. function LoopScrowViewMgr:WrapHorizontal(corners)
  345. local extents = self.max_per_line > 0 and (self.item_width * math.floor(self.item_num / self.max_per_line)) or self.item_width * self.item_num
  346. local halfExtents = extents*0.5
  347. local center = (corners[1] + corners[3]) * 0.5
  348. for i = 1,self.item_num do
  349. local item = self.item_list[i]
  350. local distance = item:GetPosition().x + self.item_width/2 - center.x
  351. if self.force_reset then
  352. local realIndex = self:GetRealIndex(item:GetPosition())
  353. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  354. -- item:SetGameObjectName(tostring(realIndex))
  355. if self.max_index > #self.item_list then
  356. item:SetVisible(true, true)
  357. end
  358. self:UpdateItem(item,i,realIndex)
  359. end
  360. elseif extents > self.mPanelDelta.x then
  361. if math.abs(distance) > halfExtents then
  362. local pos = DeepCopy(item:GetPosition())
  363. pos.x = distance < 0 and pos.x + extents or pos.x - extents
  364. local realIndex = self:GetRealIndex(pos)
  365. if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
  366. item:SetPosition(pos.x, pos.y)
  367. -- item:SetGameObjectName(tostring(realIndex))
  368. if self.max_index > #self.item_list then
  369. item:SetVisible(true, true)
  370. end
  371. self:UpdateItem(item,i,realIndex)
  372. end
  373. end
  374. end
  375. end
  376. end
  377. function LoopScrowViewMgr:UpdateItem(item,index,realIndex)
  378. if self.onInitializeItem then
  379. self.onInitializeItem(item,index,realIndex)
  380. end
  381. end
  382. function LoopScrowViewMgr:CenterOnChild(index)
  383. local floor = math.floor
  384. if self.mHorizontal then
  385. local view_num = floor(self.mPanelDelta.x/self.item_width)
  386. local endPoint = self.mTrans.sizeDelta.x - self.item_width
  387. local offset = (index - math.ceil(view_num/2)) * self.item_width
  388. for i = 1,self.item_num do
  389. local item = self.item_list[i]
  390. local pos = item:GetPosition()
  391. pos.x = (i-1)*self.item_width + offset
  392. pos.x = pos.x <= endPoint and pos.x or (offset - (i-1)*self.item_width)
  393. item:SetPosition(pos.x, pos.y)
  394. local realIndex = self:GetRealIndex(pos)
  395. self:UpdateItem(item,i,realIndex)
  396. end
  397. local content_pos = self.mTrans.anchoredPosition
  398. content_pos.x = content_pos.x - offset
  399. self.mTrans.anchoredPosition = content_pos
  400. else
  401. end
  402. end
  403. --跳转到实际索引所在的位置
  404. function LoopScrowViewMgr:JumpToChild(index)
  405. if index and index > 0 then
  406. print("==== jump to index:", index)
  407. if self.mHorizontal then
  408. if self.show_count * self.item_width > self.mPanel.sizeDelta.x then
  409. local max_index = math.min(self.max_index, self.item_num)
  410. local tran_posX = -(index - 1)*self.item_width
  411. if tran_posX < -(self.show_count * self.item_width - self.mPanel.sizeDelta.x) then
  412. tran_posX = -(self.show_count * self.item_width - self.mPanel.sizeDelta.x)
  413. end
  414. self.mTrans.localPosition = Vector2(tran_posX, self.mTrans.localPosition.y)
  415. local op_index = 1
  416. for i = 1, max_index do
  417. local item = self.item_list[i]
  418. local pos = item:GetPosition()
  419. pos.x = (i + index - 2)*self.item_width - self.offset
  420. if pos.x >= (self.show_count * self.item_width) then
  421. op_index = op_index + 1
  422. pos.x = -(op_index - index)*self.item_width - self.offset
  423. end
  424. item:SetPosition(pos.x + self.start_pos.x, pos.y + self.start_pos.y)
  425. local realIndex = self:GetRealIndex(pos)
  426. -- item:SetGameObjectName(tostring(realIndex))
  427. self:UpdateItem(item,i,realIndex)
  428. end
  429. end
  430. else
  431. if self.show_count * self.item_height > self.mPanel.sizeDelta.y then
  432. local max_index = math.min(self.max_index, self.item_num)
  433. local tran_posY = (index - 1)*self.item_height
  434. if tran_posY > (self.show_count * self.item_height - self.mPanel.sizeDelta.y) then
  435. tran_posY = self.show_count * self.item_height - self.mPanel.sizeDelta.y
  436. end
  437. self.mTrans.localPosition = Vector2(self.mTrans.localPosition.x, tran_posY)
  438. local op_index = 1
  439. for i = 1, max_index do
  440. local item = self.item_list[i]
  441. local pos = item:GetPosition()
  442. pos.y = -(math.ceil(i/self.max_per_line) + index - 2)*self.item_height
  443. if pos.y <= -(self.show_count * self.item_height) then
  444. op_index = op_index + 1
  445. pos.y = (op_index - index)*self.item_height
  446. end
  447. item:SetPosition(pos.x + self.start_pos.x, pos.y + self.start_pos.y)
  448. local realIndex = self:GetRealIndex(pos)
  449. self:UpdateItem(item,i,realIndex)
  450. end
  451. end
  452. end
  453. end
  454. end
  455. --获取展示在显示窗口的item
  456. function LoopScrowViewMgr:GetShowInViewportItem()
  457. local mPos = self.mTrans.localPosition
  458. local show_key_list = {}
  459. for k,v in pairs(self.item_list) do
  460. local bool_visible = v:GetVisible()
  461. if bool_visible then
  462. local pos = v:GetPosition()
  463. if (mPos.y+pos.y) <= self.item_height/2 and (mPos.y+pos.y) >= -self.mPanelDelta.y
  464. and (mPos.x+pos.x) >= -self.item_width/2 and (mPos.x+pos.x) <= self.mPanelDelta.x then
  465. table.insert(show_key_list, k)
  466. end
  467. end
  468. end
  469. return show_key_list
  470. end