前言

好久没写博客了.

前几周策划要求实现一个比较多功能的滚动层控件.

这个艰巨的任务就这样自然而然的落在了我这小身板上.

当然了, 只要我出手, 难度再高的需求也变得不堪一击.

哈哈哈哈

示例图

该控件功能在原生ScrollView上扩充了一下几点:

  • 在指定的范围进行节点放大, 位置偏移.
  • 点击节点可快速激活.
  • 省略 999999 个功能.

源码

 Control.ScrollView = Control.ScrollView or class("Control.ScrollView", function()
         return cc.Node:create();
     end );

 --[[
 params = {
     ["cellWidth"]         = 0,
     ["cellHeight"]         = 0,
     ["triggerLen"]        = 0,
     ["scaleXY"]         = 0,
     ["maxOffsetY"]         = 0,
     ["selCallFunc"]     = nil,    =>    selCallFunc(cell)
     ["enterCallFunc"]     = nil,    =>    enterCallFunc(cell)
     ["leaveCallFunc"]     = nil,    =>     leaveCallFunc(cell)
 }
 ]]
 function Control.ScrollView:init(params)
     self.cellWidth = params.cellWidth;
     self.cellHeight = params.cellHeight;
     self.triggerLen = params.triggerLen;
     self.scaleXY = params.scaleXY;
     self.maxOffsetY = params.maxOffsetY ;
     self.selCallFunc = params.selCallFunc or function(cell) cclog("sel cell: %s", cell); end;
     self.enterCallFunc = params.enterCallFunc or function(cell) cclog("enter cell: %s", cell); end;
     self.leaveCallFunc = params.leaveCallFunc or function(cell) cclog("leave cell: %s", cell); end;
     self.selCell = nil;
     self.curCell = nil;
     self.isTouch = false;
     self.triggerScale = self.triggerLen / self.cellWidth;
     self.cellScale = ;
     self.nodePosX = self.triggerLen * 0.5 + self.cellWidth * 0.5;
     self.elements = {};
     self.isDrag = true;

     (function()
         --    touch event 闭包.
         local downPosX;
         local downPosY;

         local function in2Value(value, minValue, maxValue)
             return value >= minValue and value <= maxValue;
         end

         local function isTouchRect(touchPoint)
             , ));
             return in2Value(touchPoint.y, worldPoint.y, worldPoint.y + self.cellHeight);
         end

         local function onTouchUp(touch)
             local touchPoint = touch:getLocation();
             self.slide:run(
                 touchPoint.x, touchPoint.y,
                 function(stepX, stepY) self:moveCells(stepX); end,
                 function() self:adjustCell(); end);
         end

         local function onTouchBegan(touch, event)
             if not self:isDragEnabeled() then
                 return ;
             end

             local touchPoint = touch:getLocation();
             local result = isTouchRect(touchPoint);
             self.curCell = nil;
             downPosX = touchPoint.x;
             downPosY = touchPoint.y;
             if result then
                 self.slide:setMark(downPosX, downPosY);
                 self.bound:stop();
             end
             return self:isVisible() and result;
         end

         local function onTouchMoved(touch, event)
             local touchPoint = touch:getLocation();

             --    调整拖动灵敏度.
              then
                 self.isTouch = false;
             end

             self.slide:setMark(downPosX, downPosY);
             self:moveCells(touchPoint.x - downPosX);
             downPosX = touchPoint.x;
             downPosY = touchPoint.y;
         end
         --    touch 响应层.
         local touchLayer = cc.Layer:create();
         local listener = cc.EventListenerTouchOneByOne:create();
         listener:registerScriptHandler( onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN );
         listener:registerScriptHandler( onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED );
         listener:registerScriptHandler( onTouchUp, cc.Handler.EVENT_TOUCH_ENDED );
         listener:registerScriptHandler( onTouchUp, cc.Handler.EVENT_TOUCH_CANCELLED );
         touchLayer:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener, touchLayer);
         self:addChild(touchLayer, );

         --    touch吞噬层.
         local listener = cc.EventListenerTouchOneByOne:create();
         listener:registerScriptHandler(
             function(touch, event)
                 return self:isVisible() and isTouchRect(touch:getLocation());
             end, cc.Handler.EVENT_TOUCH_BEGAN );
         listener:setSwallowTouches(true);
         self:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener, self);
     end)();

     --    回弹.
     self.bound = Utils:createCocos2dObject(Control.ScheduleObject);
     self:addChild(self.bound);
     --    惯性.
     self.slide = Utils:createCocos2dObject(Control.SlideInertia);
     self:addChild(self.slide);

     self:setAnchorPoint(cc.p(0.5, 0.0));
 end

 function Control.ScrollView:destroy()

 end

 function Control.ScrollView:moveCells(offsetX)
     self.nodePosX = self.nodePosX + offsetX;
     , self:getCellCount() do
         local cell = self:getCellByIndex(i);

         cell:setVisible(false);

          then
             --    移动.
             ) * self.cellWidth;
             local movetoX = curPosX;
             ;
             ;
             local minX = maxX - self.cellWidth;
             if curPosX <= maxX and curPosX >= minX then
                 if not cell.isEnter then
                     self.leaveCallFunc(self.selCell);
                     self.selCell.isEnter = false;
                     self.selCell = cell;
                     self.selCell.isEnter = true;
                     self.enterCallFunc(self.selCell);
                 end
                 movetoX = curPosX + (curPosX - maxX) * (self.triggerScale - );
                 );
                 ;
                 movetoY = ( - math.abs(curPosX - centerOffsetY) / offsetWidth) * self.maxOffsetY;
             else
                 movetoX = curPosX + (curPosX < minX ) );
             end
             cell:setPosition(movetoX, movetoY);

             --    缩放.
             local distance = math.abs(cell:getPositionX());
             ;
             local maxDistance = self.triggerLen * 0.5;
             if distance <= maxDistance then
                 scale = ( - distance / maxDistance) * (self.scaleXY - self.cellScale);
             end
             cell:setScale(self.cellScale + scale);
             cell:setVisible(true);
         end -- if.
     end -- for.
 end

 function Control.ScrollView:appendCell(cell)
     local curCount = self:getCellCount();
     self.cellScale = cell:getScale();
     self.selCell = self.selCell or cell;
     self:addChild(cell);
     cell:setAnchorPoint(cc.p(0.5, 0.0));
     cell:setPosition(self.nodePosX + curCount * self.cellWidth, 0.0);
     cell.isEnter = false;
     cell:setTouchEnabled(true);
     cell.onTouchBegan = function() self.isTouch = true; end;
     cell.onTouchEnded = function() if self.isTouch then self:gotoCell(cell); end end;
     Utils:registerButtonEvent(cell);
     table.insert(self.elements, cell);

      then
         self:adjustCell();
     end
 end

 function Control.ScrollView:removeCell(idx, isCleanup)
     local cell = self:getCellByIndex(idx);
     cell:removeFromParentAndCleanup(isCleanup);
     table.remove(self.elements, idx);

      then
         self:adjustCell();
     end
 end

 function Control.ScrollView:adjustCell()
     local function call()
         local cell = self.curCell or self.selCell;
         local pointX = cell:getPositionX();
         local step = -pointX * 0.1;
         if math.abs(step) < 0.1 then
             self.curCell = nil;
             self.selCallFunc(cell);
             self.bound:stop();
         end
         self:moveCells(step);
     end
      then
         call();
         self.bound:run(call, 0.01);
     end
 end

 function Control.ScrollView:getCellCount()
     return #(self.elements);
 end

 function Control.ScrollView:gotoCell(cell)
     if cell:getParent() == self then
         self.curCell = cell;
         self:adjustCell();
     end
 end

 function Control.ScrollView:getSelCell()
     return self.selCell;
 end

 function Control.ScrollView:getCellByTag(tag)
     return self:getChildByTag(tag);
 end

 function Control.ScrollView:getCellByIndex(idx)
     return self.elements[idx];
 end

 function Control.ScrollView:setDragEnabeled(isDrag)
     self.isDrag = isDrag;
 end

 function Control.ScrollView:isDragEnabeled()
     return self.isDrag;
 end

该控件实质是一个cc.Node.

内部没有使用cc.ScrollView.

因为引擎自带的控件相当不好扩充. 最主要的是, 我喜欢造轮子.

该控件内部有一个 滑动对象, 该对象用于控制惯性.

该控件通过

newCallFunc 创造子节点.

SelCallFunc 节点最大化时回调.

enterCallFunc 节点开始变大时回调.

leaveCallFunc 节点恢复原状时回调.

移动子节点时, 需要对子节点逐个遍历移动.

这里占用了很大的性能开销.

不过, 这是不可能的.

在超出范围的子节点将被忽略, 并且隐藏.

并且内部使用了跳帧技巧.

根据节点数量变化跳帧数.

300个骨骼动画拖动时, 最低可在30帧以上, 平均45帧左右.

子节点是逐帧加载, 避免界面长时间不显示.

例子下载

例子链接

改善部分

忽略屏幕以外节点的移动.

裁剪屏幕以外的节点.

性能翻倍.

cocos2dx 实现华丽丽的滚动层.的更多相关文章

  1. Cocos2dx中利用双向链表实现无限循环滚动层

    [Qboy原创] 在Cocos2dX 3.0 中已经实现一些牛逼的滚动层,但是对于有一些需要实现循环滚动的要求确没有实现,笔者在前段时间的一个做了一个游戏,需求是实现在少有的(13个)英雄中进行循环滚 ...

  2. 【Cocos2dx 3.3 Lua】滚动字幕

    参考资料:     http://blog.csdn.net/jackystudio/article/details/12991977   1.原理         通过调用update来更新位置达到 ...

  3. 跟随屏幕滚动层、遮罩层、获取Div相对定位、整个屏幕、html文档的jquery基本操作

    一.层跟随屏幕滚动 <div style="width:120px;height:120px;border:1px solid red; position:absolute; left ...

  4. cocos2dx一个场景添加多个层

    首先创建两个layer,以下是头文件 #pragma once#include "cocos2d.h"USING_NS_CC;class BackgroundLayer : pub ...

  5. sortable.js 华丽丽的排序

    首先导入这几个资源 <link href="/css/jquery-ui-1.10.3.custom.css" rel="stylesheet" type ...

  6. 【安富莱原创开源应用第1期】花式玩转网络摄像头之TCP上位机软件实现,高端大气上档次,速度2MB/S,华丽丽的界面效果

    说明:1.例子是两年前做的,一直没有顾上整理出来,今天特地整理出来,开源出来给大家玩.2.上位机是emWin模拟器开发的,大家估计很难猜到,所以你会emWin话的,就可以轻松制作上位机.做些通信和控制 ...

  7. POJ1475 Pushing Boxes 华丽丽的双重BFS

    woc累死了写了两个半小时...就是BFS?我太菜了... 刚开始以为让人预先跑一遍BFS,然后一会儿取两节加起来就好了,结果发现求出来的最短路(就是这个意思)会因箱子的移动而变化....我死了QWQ ...

  8. Xamarin.forms 自定义dropdownview控件

    一 基本说明 想用xamarin做个像美团这样的下拉列表进行条件选择的功能,但是但是找了半天好像没有现成的,也没有其他类似的控件可以走走捷径,再则也没有找到popwindow之类的东东,这里只好使用s ...

  9. 移动端页面 弹出框滚动,底部body锁定,不滚动 / 微信网页禁止回弹效果

    需求:页面有弹出层菜单,当弹出层菜单超出屏幕可视区域时,不能滚动.加上滚动后,底部body的滚动事件如何禁止,加上了overflow:hidden;还是不可用. 如下图:地区弹出框可以滚动,而底部的b ...

随机推荐

  1. Android Fragment实现分屏

    在项目中碰到一个问题,新开发一个平板APP,项目要求是把原来的一个手机端APP放在项目左侧显示,右侧添加新加的功能. 首先想到了Fragment,以前做过Fragment的一些简单的Demo,但是都没 ...

  2. Linux学习笔记1——Linux的目录结构

    / 是根目录 ~是主目录 bin 存放二进制可执行文件(Is,cat,mkdir等) boot 存放用于系统引导时使用的各种文件 dev 用于存放设备文件 etc 存放系统配置文件 home 存放所有 ...

  3. 【转】Unity3D NGUI事件 UIEvents

    原创文章如需转载请注明:转载自 脱莫柔Unity3D学习之旅 QQ群:[119706192] 本文链接地址: Unity3D NGUI事件 UIEvents UIEvents-事件系统void OnH ...

  4. ListView的性能优化之convertView和viewHolder

    转载请注明出处 最近碰到的面试题中经常会碰到问"ListView的优化"问题.所以就拿自己之前写的微博客户端的程序做下优化. 自己查了些资料,看了别人写的博客,得出结论,ListV ...

  5. 406. Queue Reconstruction by Height

    一开始backtrack,设计了很多剪枝情况,还是TLE了 ..后来用PQ做的. 其实上面DFS做到一半的时候意识到应该用PQ做,但是不确定会不会TLE,就继续了,然后果然TLE了.. PQ的做法和剪 ...

  6. c#基础语言编程-多态

    语言中的多态性是为了使程序有扩展性,为实现多态性,在程序中体现为接口.抽象类.父类.具体类. 接口就是一种规范,解决了多重继承的问题,类似一种规范,告诉我要做什么,具有什么能力,在接口中定义写行为属性 ...

  7. winform datagridview如何获取索引 分类: DataGridView 2014-04-11 13:42 216人阅读 评论(0) 收藏

    datagridview.CurrentCell.RowIndex;            是当前活动的单元格的行的索引 datagridview.SelectedRows  ;           ...

  8. android 58 jvm和dvm的区别(Dalvil VM)

    java程序在jvm和dvm的执行过程: #jvm和dvm的区别(Dalvil VM) 谷歌刚开发的安卓系统用的就是JVM,JVM版权属于sun公司也就是Oracle公司,后来用的是DVM,由于版权问 ...

  9. Qt自定义控件(插件)并添加到QtDesigher

    之前使用Qt的时候都是手写代码的(因为批量按钮可以使用数组实现),但当界面越来越复杂时,这种开发效率就太低了; 后来就开始使用QtDesigner,但要使QtDesigner支持我自己写的控件,需要提 ...

  10. 支付宝手机网站支付流程(Node实现)

    前言 公司M站要接入支付宝,借机研究了一下支付宝的支付流程.毕竟,只有公司才能拿到支付接口权限. 主要参考文档: https://doc.open.alipay.com/doc2/detail?tre ...