频道栏目
首页 > 资讯 > 其他 > 正文

cocos2dx 实现华丽丽的滚动层.

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

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站