抽空做了一個ugui的無限滾動的效果。只做了一半(向下無限滾動)。網上也看了很多教程,感覺還是按照自己的思路來寫可能比較好。搭建如下:
content節點不添加任何組件。布局組件默認是會重新排版子節點的,所以如果子節點的位置變化,會重新排版,不能達到效果。size fitter組件也不加,自己寫代碼調整size大小(不調整大小,無法滑動)。
最主要的實現過程就是用queue來搬運cell。在向下滾動的過程中(鼠標上滑),頂部滑出view port的cell被搬運到底部續上。這點類似于queue的先見先出原則,再把dequeue出來的元素添加到末尾,就很類似于scrollview的無限滾動的原理了。在鼠標上滑的過程中,content的posy值是一直增加的,所以觸發滾動的條件就可以設定為位移之差大于cell的高度值即可。
數據的刷新,數據到頭之后,不能再次進行滾動輪換了,這里用一組值來記錄初始化的一組cell顯示的是數據的哪一段。例如headnum和tainum。比如用20個cell顯示100條數據。初始化后,headnum就是0,tailnum就是19。上滑一行數據后,headnum=4,tailnum=23(這里假設是20個cell排成4列)。
下面是完整代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
public class uiscrollviewtest : monobehaviour { public recttransform content; public gameobject cell; // cell的初始化個數 public int cellamount = 0; // 鼠標上滑時,存儲cell的queue。正序存儲 public queue f_cellquee = new queue(); // 鼠標下滑時,存儲cell的queue。到序存儲 public queue b_cellquee = new queue(); // cell的size public vector2 cellsize = new vector2(100,100); // cell的間隔 public vector2 celloffset = new vector2(0,0); // 列數 public int columncount = 0; private int rowcount; // 上一次content的位置 public float lastpos; // 滾動的次數 public int loopcount = 0; // cell顯示的數據段的開頭和結尾序號 public int headnum = 0; public int tailnum; public sprite[] sp; public list<sprite> data; void start() { for ( int i = 0; i < sp.length; i++) { data.add(sp[i]); } initialscrollview(data); tailnum = cellamount-1; lastpos = content.localposition.y; //debug.logerror("行數是:::" + rowcount); //debug.logerror("+++++++++++++++++ " + (5>>3)); } void update() { // 觸發滾動。 if (content.localposition.y - lastpos > cellsize.y && data.count - cellamount - loopcount*columncount >0) { //debug.logerror("11111111111 " + (data.count - cellamount - loopcount * columncount)); loopscrolview(data); lastpos = content.localposition.y; } } // 初始化cell void initialscrollview(list<sprite> data) { for ( int i = 0; i < cellamount; i++) { gameobject obj = instantiate(cell.gameobject); obj.transform.setparent(content); obj.name = "cell0" + i.tostring(); obj.transform.getchild(0).getcomponent<text>().text = "cell0" +i.tostring(); // 顯示默認的數據 obj.getcomponent<image>().sprite = data[i]; } // 初始化queue for ( int i = content.childcount-1; i >= 0; i--) { b_cellquee.enqueue(content.getchild(i).gameobject); } for ( int i = 0; i < content.childcount; i++) { f_cellquee.enqueue(content.getchild(i).gameobject); } // 計算行數 if (cellamount % columncount >0) { rowcount = cellamount / columncount + 1; } else { rowcount = cellamount / columncount; } // 排列cell的位置 int index = 0; for ( int r = 1; r <= rowcount; r++) { for ( int c = 1; c <= columncount; c++) { if (index < cellamount) { vector2 pos = new vector2(cellsize.x / 2 + (cellsize.x + celloffset.x) * (c-1), -cellsize.y / 2 - (celloffset.y + cellsize.y) * (r-1)); content.getchild(index).getcomponent<recttransform>().setinsetandsizefromparentedge(recttransform.edge.top, 0, 100); content.getchild(index).getcomponent<recttransform>().setinsetandsizefromparentedge(recttransform.edge.left, 0, 100); content.getchild(index).getcomponent<recttransform>().anchoredposition = pos; index++; } } } vector2 v = content.sizedelta; // 初始化content的size content.sizedelta = new vector2(v.x, rowcount * cellsize.y + celloffset.y*(rowcount-1)); } /// 保持content的大小,這里是保持大小為在cell的行數基礎上,向下多出bottomcount行的距離 void setcontentsize( int uppercount, int bottomcount) { if (content.sizedelta != new vector2(content.sizedelta.x, content.sizedelta.y + bottomcount * (cellsize.y + celloffset.y))) { content.sizedelta = new vector2(content.sizedelta.x, content.sizedelta.y + bottomcount*(cellsize.y + celloffset.y)); } } // 計算頂部的cell輪換到底部時的位置。以當前最后一行的最后一個cell的位置為基準計算。 void setbottomcellposition( int index, recttransform rect, vector2 pos) { vector2 v = vector2.zero; if (cellamount % columncount == 0) // 整除。每一行都滿的情況。 { float x = pos.x - cellsize.x * (columncount - index-1) - celloffset.x * (columncount-index-1); float y = pos.y - cellsize.y - celloffset.y; v = new vector2(x,y); } // 出現不滿行的情況。例如數據有103個,可以用23個cell來輪換。這樣就會出現不滿行的情況。 // 這種情況下是頂部的一行cell順次接到底部不滿的行。例如23號cell后面接1號和2號cell,3號和4號cell填充到第“7”行 else if (cellamount % columncount + index+1<=columncount) { float x = pos.x + cellsize.x * (index+1) + celloffset.x * (index+1); float y = pos.y; v = new vector2(x, y); } else { float x = pos.x - cellsize.x * (columncount - index-1) - celloffset.x * (columncount - index-1); float y = pos.y - cellsize.y - celloffset.y; v = new vector2(x, y); } //debug.logerror("++++++++++++++ " + pos+ " "+ v); rect.anchoredposition = v; rect.setaslastsibling(); } // 計算底部的cell輪換到頂部是的位置,基準位置是當前行的第一個cell。 void setuppercellposition( int index, recttransform rect, vector2 pos) { vector2 v = vector2.zero; if (cellamount % columncount == 0) // 整除 { float x = pos.x + cellsize.x * index + celloffset.x * index; float y = pos.y + cellsize.y + celloffset.y; v = new vector2(x, y); } //else if (cellamount % columncount + index + 1 <= columncount) //{ // float x = pos.x + cellsize.x * (index + 1) + celloffset.x * (index + 1); // float y = pos.y; // v = new vector2(x, y); //} //else //{ // float x = pos.x - cellsize.x * (columncount - index - 1) - celloffset.x * (columncount - index - 1); // float y = pos.y - cellsize.y - celloffset.y; // v = new vector2(x, y); //} //debug.logerror("++++++++++++++ " + pos+ " "+ v); rect.anchoredposition = v; rect.setasfirstsibling(); } // 鼠標上滑時,顯示當前cell的數據。同時記錄數據段的序號遞增。 void showrestcelldata(image cell, int index) { if (tailnum< data.count-1) { debug.logerror( "當前的序號是::::" + tailnum); tailnum++; headnum++; cell.sprite = data[tailnum]; } } void showpreviouscelldata(image cell, int index) { if (headnum > 0) { debug.logerror( "當前的序號是::::" + headnum); tailnum--; headnum--; cell.sprite = data[headnum]; } } // 輪換的函數。每次亂換一行的cell。 void loopscrolview(list<sprite> data) { setcontentsize(0, 1); loopcount++; recttransform rect2 = content.getchild(content.childcount - 1).getcomponent<recttransform>(); for ( int i = 0; i < columncount; i++) { gameobject obj = f_cellquee.dequeue() as gameobject; recttransform rect = obj.getcomponent<recttransform>(); showrestcelldata(obj.getcomponent<image>(), i); setbottomcellposition(i, rect, rect2.anchoredposition); f_cellquee.enqueue(obj); } } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/Tong1993222/article/details/80163764