1 --
2 --滑动惯性.
3 --
4 Control.SlideInertia = Control.SlideInertia or class("Control.SlideInertia", function()
5return cc.Node:create();
6end );
7
8 function Control.SlideInertia:init()
9self.schId = 0;
10 end
11
12 function Control.SlideInertia:destroy()
13self.schId = Utils:unSchedule(self.schId);
14 end
15
16 function Control.SlideInertia:setMark(x, y)
17self.time = os.time();
18self.mark = cc.p(x, y);
19self.schId = Utils:unSchedule(self.schId);
20 end
21
22 function Control.SlideInertia:run(x, y, frameCallFunc, endCallFunc)
23frameCallFunc = frameCallFunc or function() cclog("default frameCallFunc") end;
24endCallFunc = endCallFunc or function() cclog("default endCallFunc") end;
25
26local curTime = os.time();
27local diffTime = math.max(curTime - self.time, 1);
28local stepX = (x - self.mark.x) / diffTime;
29local stepY = (y - self.mark.y) / diffTime;
30local function call()
31frameCallFunc(stepX, stepY);
32stepX = stepX * 0.8;
33stepY = stepY * 0.8;
34if math.abs(stepX) < 1 and math.abs(stepY) < 1 then
35endCallFunc();
36self.schId = Utils:unSchedule(self.schId);
37end
38end
39if math.abs(stepX) > 0 or math.abs(stepY) > 0 then
40self.schId = Utils:unSchedule(self.schId);
41self.schId = Utils:runSchedule(call, 0.01);
42end
43 end
44
45
46 --
47 --滚动层.
48 --
49 Control.ScrollView = Control.ScrollView or class("Control.ScrollView", function()
50return cc.Node:create();
51end );
52
53 --[[
54 params = {
55["count"]= 0,
56["cellWidth"]= 0,
57["cellHeight"]= 0,
58["triggerLen"]= 0,
59["scaleXY"]= 0,
60["maxOffsetY"]= 0,
61["newCallFunc"]= nil,=>newCallFunc(i)
62["selCallFunc"]= nil,=>selCallFunc(cell)
63["enterCallFunc"]= nil,=>enterCallFunc(cell)
64["leaveCallFunc"]= nil,=>leaveCallFunc(cell)
65 }
66 ]]
67
68 function Control.ScrollView:init(params)
69local count = params["count"];
70local cellWidth = params["cellWidth"];
71local cellHeight = params["cellHeight"];
72local triggerLen = params["triggerLen"];
73local scaleXY = params["scaleXY"];
74local maxOffsetY = params["maxOffsetY"] or 0;
75local newCallFunc = params["newCallFunc"];
76local selCallFunc = params["selCallFunc"] or function(cell) cclog("sel cell: %s", cell); end;
77local enterCallFunc = params["enterCallFunc"] or function(cell) cclog("enter cell: %s", cell); end;
78local leaveCallFunc = params["leaveCallFunc"] or function(cell) cclog("leave cell: %s", cell); end;
79local selCell = nil;
80local curCell = nil;
81local triggerScale = triggerLen / cellWidth;
82local downPosX;
83local downPosY;
84local cellScale = 1;
85local elements = {};
86local nodePosX = triggerLen * 0.5 + cellWidth * 0.5;
87local isTouch = false;
88local isLoadEnd = false;
89local skipFrame = math.floor(count / 50) + 1;
90local skipCount = 0;
91local viewSize = cc.Director:getInstance():getVisibleSize();
92
93local function in2Value(value, minValue, maxValue)
94return value >= minValue and value <= maxValue;
95end
96
97--移动所有节点.
98local function moveCells(offsetX)
99nodePosX = nodePosX + offsetX;
100for i = 1, count do
101local cell = elements[i];
102if math.abs(nodePosX + i * cellWidth) < viewSize.width + cellWidth / 2 then
103cell:setVisible(true);
104--移动.
105(function()
106local curPosX = nodePosX + (i - 1) * cellWidth;
107local movetoX = curPosX;
108local movetoY = 0;
109local maxX = triggerLen / 2;
110local minX = maxX - cellWidth;
111if curPosX <= maxX and curPosX >= minX then
112if not cell.isEnter then
113leaveCallFunc(selCell);
114selCell.isEnter = false;
115selCell = cell;
116selCell.isEnter = true;
117enterCallFunc(cell);
118end
119movetoX = curPosX + (curPosX - maxX) * (triggerScale - 1);
120local centerOffsetY = (maxX - cellWidth / 2);
121local offsetWidth = (maxX - minX) / 2;
122movetoY = (1 - math.abs(curPosX - centerOffsetY) / offsetWidth) * maxOffsetY;
123else
124movetoX = curPosX + (curPosX < minX and -cellWidth * (triggerScale - 1) or 0);
125end
126cell:setPositionX(movetoX);
127cell:setPositionY(movetoY);
128end)();
129--缩放.
130(function()
131local distance = math.abs(cell:getPositionX());
132local scale = 0;
133local maxDistance = triggerLen * 0.5;
134if distance <= maxDistance then
135scale = (1 - distance / maxDistance) * (scaleXY - cellScale);
136end
137cell:setScale(cellScale + scale);
138end)();
139else
140cell:setVisible(false);
141end
142end
143end
144
145--调整位置.
146local function adjustPosition()
147local function call()
148local cell = curCell and curCell or selCell;
149local pointX = cell:getPositionX();
150local step = -pointX * 0.1;
151if math.abs(step) < 0.1 then
152curCell = nil;
153selCallFunc(cell);
154self.schSlideId = Utils:unSchedule(self.schSlideId);
155end
156moveCells(step);
157end
158self.schSlideId = Utils:unSchedule(self.schSlideId);
159self.schSlideId = Utils:runSchedule(call, 0.01);
160end
161
162local function isTouchRect(touchPoint)
163local worldPoint = self:convertToWorldSpace(cc.p(0, 0));
164return in2Value(touchPoint.y, worldPoint.y, worldPoint.y + cellHeight);
165end
166
167local function onTouchUp(touch)
168local function frameCallFunc(stepX, stepY)
169moveCells(stepX);
170end
171local function endCallFunc()
172adjustPosition();
173end
174local touchPoint = touch:getLocation();
175self.slide:run(touchPoint.x, touchPoint.y, frameCallFunc, endCallFunc);
176end
177
178local function onTouchBegan(touch, event)
179skipCount = 0;
180local touchPoint = touch:getLocation();
181local result = isTouchRect(touchPoint);
182curCell = nil;
183downPosX = touchPoint.x;
184downPosY = touchPoint.y;
185if result then
186self.slide:setMark(downPosX, downPosY);
187self.schSlideId = Utils:unSchedule(self.schSlideId);
188end
189return result;
190end
191
192local function onTouchMoved(touch, event)
193if skipCount % skipFrame == 0 then
194local touchPoint = touch:getLocation();
195
196--调整拖动灵敏度.
197if math.abs(downPosX - touchPoint.x) > 5 then
198isTouch = false;
199end
200
201self.slide:setMark(downPosX, downPosY);
202moveCells(touchPoint.x - downPosX);
203downPosX = touchPoint.x;
204downPosY = touchPoint.y;
205end
206skipCount = skipCount + 1;
207end
208
209local function onTouchEnded(touch, event)
210onTouchUp(touch);
211end
212
213local function onTouchCancelled(touch, event)
214onTouchUp(touch);
215end
216
217local function setCurCell(cell)
218if isTouch == true then
219curCell = cell;
220adjustPosition();
221end
222end
223
224local function loadEnd()
225isLoadEnd = true;
226
227self.schLoadId = Utils:unSchedule(self.schLoadId);
228
229--touch 响应层.
230local touchLayer = cc.Layer:create();
231local listener = cc.EventListenerTouchOneByOne:create();
232listener:registerScriptHandler( onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN );
233listener:registerScriptHandler( onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED );
234listener:registerScriptHandler( onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED );
235listener:registerScriptHandler( onTouchCancelled, cc.Handler.EVENT_TOUCH_CANCELLED );
236touchLayer:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener, touchLayer);
237self:addChild(touchLayer);
238
239--touch吞噬层.
240local listener = cc.EventListenerTouchOneByOne:create();
241listener:registerScriptHandler(
242function(touch, event)
243return isTouchRect(touch:getLocation());
244end, cc.Handler.EVENT_TOUCH_BEGAN );
245listener:setSwallowTouches(true);
246self:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener, self);
247
248adjustPosition();
249end
250
251self.schSlideId = 0;
252self.schLoadId = 0;
253self.slide = Utils:createCocos2dObject(Control.SlideInertia);
254self:addChild(self.slide);
255self:setAnchorPoint(cc.p(0.5, 0.0));
256
257--异步加载.
258local num = 0;
259self.schLoadId = Utils:runSchedule(function()
260local cell = newCallFunc(num + 1);
261self:addChild(cell);
262cell:setAnchorPoint(cc.p(0.5, 0.0));
263cell:setPosition(nodePosX + num * cellWidth, 0.0);
264cell.isEnter = false;
265cell:setTouchEnabled(true);
266cell.onTouchBegan = function() if isLoadEnd then isTouch = true; end end;
267cell.onTouchEnded = function() setCurCell(cell); end;
268Utils:registerButtonEvent(cell);
269table.insert(elements, cell);
270cellScale = cell:getScale();
271selCell = selCell and selCell or cell;
272
273num = num + 1;
274if num == count then
275loadEnd();
276end
277end, 0.016);
278 end
279
280 function Control.ScrollView:destroy()
281self.schSlideId = Utils:unSchedule(self.schSlideId);
282self.schLoadId = Utils:unSchedule(self.schLoadId);
283 end
复制代码
该控件实质是一个cc.Node.
内部没有使用cc.ScrollView.
因为引擎自带的控件相当不好扩充. 最主要的是, 我喜欢造轮子.
该控件内部有一个 滑动对象, 该对象用于控制惯性.
该控件通过
newCallFunc 创造子节点.
SelCallFunc 节点最大化时回调.
enterCallFunc 节点开始变大时回调.
leaveCallFunc 节点恢复原状时回调.
移动子节点时, 需要对子节点逐个遍历移动.
这里占用了很大的性能开销.
不过, 这是不可能的.
在超出范围的子节点将被忽略, 并且隐藏.
并且内部使用了跳帧技巧.
根据节点数量变化跳帧数.
300个骨骼动画拖动时, 最低可在30帧以上, 平均45帧左右.