1 lua控件基类
_class = {}
local UIBase = class("UIBase",cc.Node)
function UIBase:ctor()
-- 触摸监听事件
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(function ( touch,event )
return self:onPanelTouchBegan(touch,event)
end,cc.Handler.EVENT_TOUCH_BEGAN)
listener:registerScriptHandler(function ( touch,event )
return self:onPanelTouchMoved(touch,event)
end,cc.Handler.EVENT_TOUCH_MOVED)
listener:registerScriptHandler(function ( touch,event )
return self:onPanelTouchEnded(touch,event)
end,cc.Handler.EVENT_TOUCH_ENDED)
self.listener = listener
local eventDispatch = self:getEventDispatcher()
eventDispatch:addEventListenerWithSceneGraphPriority(listener,self) -- self:响应事件的对象
-- script handler
local function onNodeEvent(event)
if "enter" == event then
self:onEnter()
elseif "exit" == event then
self:onExit()
end
end
self:registerScriptHandler(onNodeEvent)
end
function UIBase.isTouchInside(node,touch)
local touchLoc = touch:getLocation()
touchLoc = node:getParent():convertToNodeSpace(touchLoc)
if not cc.rectContainsPoint(node:getBoundingBox(), touchLoc) then
return false
end
return true
end
function UIBase:onEnter()
end
function UIBase:onExit()
end
function UIBase:onPanelTouchBegan( touch,event )
-- body
end
function UIBase:onPanelTouchMoved( touch,event )
-- body
end
function UIBase:onPanelTouchEnded( touch,event )
-- body
end
_class.UIBase = UIBase
2 各种自定义滑动选择控件
2.1 类型1
效果
采用的曲线方程
lua源码
参考(http://blog.csdn.net/ccy0815ccy/article/details/43924895)
local UIRotateMenu1 = class("UIRotateMenu1",_class.UIBase)
UIRotateMenu1.AniDuration = 0.5 -- 运动延时
UIRotateMenu1.Factror = 2 -- 控制曲线形态
UIRotateMenu1.ItemScrollFactor = 1/5 -- 滑过1/5宽度对应滑动过一个item
UIRotateMenu1.IndexScrollFactor = 1/3 -- 滑动超过1/3自动转至下个Index
function UIRotateMenu1:ctor()
_class.UIBase.ctor(self)
self._itemT = {}
self._index = 0 -- 中心位置Item index
self._lastindex = 0
local cs = cc.Director:getInstance():getWinSize()
self:setContentSize(cs)
-- self:setContentSize(cc.size(cs.width*2/3,cs.height*2/3))
end
function UIRotateMenu1:title()
return "Moke And TianTian"
end
function UIRotateMenu1:addMenuItem(item)
local cs = self:getContentSize()
item:setPosition(cc.p(cs.width/2,cs.height/2))
self:addChild(item)
table.insert(self._itemT,item)
self:reset()
self:updatePosWithAni()
end
function UIRotateMenu1:reset()
self._index = 0
self._lastindex = 0
end
-- 矫正中心Index
function UIRotateMenu1:rectify( deltaX )
local isforward = nil
if deltaX then
if deltaX > 0 then
isforward = true
else
isforward = false
end
end
local idx = self:_getIndex()
if idx < 0 then
idx = idx + #self._itemT
elseif idx > (#self._itemT - 1) then
idx = idx - #self._itemT
end
if isforward == true then
idx = math.floor(idx + self.IndexScrollFactor)
elseif isforward == false then
idx = math.floor(idx + 2*self.IndexScrollFactor)
end
self:_setIndex(idx)
end
function UIRotateMenu1:updatePos()
for k,v in pairs(self._itemT) do
v:setPosition(self:_getPos(k-1))
v:setScale(self:_getScale(k-1))
v:setRotation3D(cc.vec3(0,self:_getRotation(k-1),0))
v:setLocalZOrder(self:_getZorder(k-1))
end
end
function UIRotateMenu1:updatePosWithAni()
for k,v in pairs(self._itemT) do
v:stopAllActions()
end
for k,v in pairs(self._itemT) do
local newpos = self:_getPos(k-1)
v:moveTo({time = self.AniDuration, x = newpos.x, y = newpos.y})
v:scaleTo({time = self.AniDuration, scale = self:_getScale(k-1)})
v:rotateTo({time = self.AniDuration, rotation = cc.vec3(0,self:_getRotation(k-1),0)})
v:setLocalZOrder(self:_getZorder(k-1))
end
local delayTimeAct = cc.DelayTime:create(self.AniDuration)
local sequence = cc.Sequence:create(delayTimeAct,cc.CallFunc:create(handler(self,self.callFunc)))
self:runAction(sequence)
end
function UIRotateMenu1:_getPos(idx)
local cs = self:getContentSize()
local deltaX = self:curveFunc(self:transIdxToCurveFuncVar(idx),cs.width/2)
return cc.p(cs.width/2 + deltaX,cs.height/2)
end
function UIRotateMenu1:_getZorder(idx)
return -math.abs(idx-self:_getIndex())
end
function UIRotateMenu1:_getScale(idx)
return 1- math.abs(self:curveFunc(self:transIdxToCurveFuncVar(idx),1))
end
function UIRotateMenu1:_getRotation(idx)
return self:curveFunc(self:transIdxToCurveFuncVar(idx),60)
end
function UIRotateMenu1:_getIndex()
return self._index
end
function UIRotateMenu1:_setIndex( curTmpIdx )
self._index = curTmpIdx
end
function UIRotateMenu1:callFunc()
self:rectify()
local curSp = self._itemT[self:_getIndex() + 1]
if curSp then
self.label:setString(curSp:getName())
end
end
function UIRotateMenu1:onPanelTouchBegan( touch,event )
-- cclog("UIRotateMenu1:onPanelTouchBegan")
if not self.isTouchInside(self,touch) then
return false
end
for k,v in pairs(self._itemT) do
v:stopAllActions()
end
return true
end
function UIRotateMenu1:onPanelTouchMoved( touch,event )
local deltaX = touch:getDelta().x
local curTmpIdx = self:transMoveLenToVar(deltaX)
self:_setIndex(curTmpIdx)
self:updatePos()
end
function UIRotateMenu1:onPanelTouchEnded( touch,event )
local deltaX = touch:getLocation().x - touch:getStartLocation().x
self:rectify(deltaX)
self:updatePosWithAni()
end
-- 将移动长度转为核心变量
function UIRotateMenu1:transMoveLenToVar(moveLen)
local cs = self:getContentSize()
return self._index - moveLen/(cs.width * self.ItemScrollFactor)
end
-- 将当前Idx转为曲线方程自变量
function UIRotateMenu1:transIdxToCurveFuncVar(idx)
return idx - self:_getIndex()
end
function UIRotateMenu1:curveFunc(x,width) -- x:deltaIdx
return width * x/(math.abs(x)+self.Factror)
end
function UIRotateMenu1:onEnter()
cclog("UIRotateMenu1:onEnter")
-- title
local label = cc.Label:createWithTTF(self.title(), "fonts/arial.ttf", 32)
self:addChild(label)
label:setAnchorPoint(cc.p(0.5, 0.5))
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) )
-- index label
label = cc.Label:createWithTTF("", "fonts/arial.ttf", 22)
label:setColor(cc.c3b(255,0,0))
self:addChild(label)
label:setAnchorPoint(cc.p(0.5, 0.5))
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 80) )
self.label = label
local ball = cc.Sprite:create("Images/moke1.jpg")
ball:setName("moke1")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke2.jpg")
ball:setName("moke2")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke3.jpg")
ball:setName("moke3")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke4.jpg")
ball:setName("moke4")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke5.jpg")
ball:setName("moke5")
self:addMenuItem(ball)
-- ball = cc.Sprite:create("Images/moke6.jpg")
-- self:addMenuItem(ball)
end
function UIRotateMenu1:onExit()
end
function UIRotateMenu1Main()
cclog("UIRotateMenu1Main")
local scene = cc.Scene:create()
local rotateMenu = UIRotateMenu1:create()
scene:addChild(rotateMenu)
scene:addChild(CreateBackMenuItem())
return scene
end
2.2 类型2
效果
Lua源码(
参:http://blog.csdn.net/ccy0815ccy/article/details/41519767
)
local UIRotateMenu2 = class("UIRotateMenu2",_class.UIBase)
UIRotateMenu2.AniDuration = 0.5 -- 运动延时
UIRotateMenu2.Factror = 2 -- 控制曲线形态
UIRotateMenu2.ItemScrollFactor = 1/5 -- 滑过1/5宽度对应滑动过一个item
UIRotateMenu2.IndexScrollFactor = 1/3 -- 滑动超过1/3自动转至下个Index
function UIRotateMenu2:ctor()
_class.UIBase.ctor(self)
self._itemT = {}
self._index = 0 -- 中心位置Item index
self._unitAngle = 0 -- 两个item间相隔的离心角(单位离心角)
local cs = cc.Director:getInstance():getWinSize()
self:setContentSize(cs)
-- self:setContentSize(cc.size(cs.width*2/3,cs.height*2/3))
self.majorSemiAxis = cs.width/4 -- 长半轴
self.minorSemiAxis = cs.height/4 -- 短半轴
end
function UIRotateMenu2:title()
return "Moke And TianTian"
end
function UIRotateMenu2:addMenuItem(item)
local cs = self:getContentSize()
item:setPosition(cc.p(cs.width/2,cs.height/2))
self:addChild(item)
table.insert(self._itemT,item)
self:reset()
self:updatePosWithAni()
end
function UIRotateMenu2:reset()
self._index = 0
self._unitAngle = 2 * math.pi / #self._itemT
end
function UIRotateMenu2:rectify( deltaX )
local isforward = nil
if deltaX then
if deltaX > 0 then
isforward = true
else
isforward = false
end
end
local idx = self:_getIndex()
if idx < 0 then
idx = idx + #self._itemT
elseif idx > (#self._itemT - 1) then
idx = idx - #self._itemT
end
if isforward == true then
idx = math.floor(idx + self.IndexScrollFactor)
elseif isforward == false then
idx = math.floor(idx + 2*self.IndexScrollFactor)
end
self:_setIndex(idx)
end
function UIRotateMenu2:updatePos()
for k,v in pairs(self._itemT) do
v:setPosition(self:_getPos(k-1))
v:setScale(self:_getScale(k-1))
v:setOpacity(self:_getOpacity(k-1))
-- v:setRotation3D(cc.vec3(0,self:_getRotation(k-1),0))
v:setLocalZOrder(self:_getZorder(k-1))
end
end
function UIRotateMenu2:updatePosWithAni()
for k,v in pairs(self._itemT) do
v:stopAllActions()
end
for k,v in pairs(self._itemT) do
local newpos = self:_getPos(k-1)
v:moveTo({time = self.AniDuration, x = newpos.x, y = newpos.y})
v:scaleTo({time = self.AniDuration, scale = self:_getScale(k-1)})
v:fadeTo({time = self.AniDuration, opacity = self:_getOpacity(k-1)})
-- v:rotateTo({time = self.AniDuration, rotation = cc.vec3(0,self:_getRotation(k-1),0)})
v:setLocalZOrder(self:_getZorder(k-1))
end
local delayTimeAct = cc.DelayTime:create(self.AniDuration)
local sequence = cc.Sequence:create(delayTimeAct,cc.CallFunc:create(handler(self,self.callFunc)))
self:runAction(sequence)
end
function UIRotateMenu2:_getPos(idx)
local cs = self:getContentSize()
local idxAngle = self:transIdxToCurveFuncVar(idx)
local posx = self:curveFuncSin(idxAngle,cs.width/2,self.majorSemiAxis)
local posy = self:curveFuncCos(idxAngle,cs.height/2,-self.minorSemiAxis)
return cc.p(posx,posy)
end
function UIRotateMenu2:_getZorder(idx)
local cs = self:getContentSize()
local idxAngle = self:transIdxToCurveFuncVar(idx)
return self:curveFuncCos(idxAngle,cs.height/2,self.minorSemiAxis)
end
-- scale: 0.5~1
function UIRotateMenu2:_getScale(idx)
local idxAngle = self:transIdxToCurveFuncVar(idx)
return self:curveFuncCos(idxAngle,0.75,0.25)
end
-- opcacity: 129~255
function UIRotateMenu2:_getOpacity(idx)
local idxAngle = self:transIdxToCurveFuncVar(idx)
return self:curveFuncCos(idxAngle,192,63)
end
function UIRotateMenu2:_getRotation(idx)
end
function UIRotateMenu2:_getIndex()
return self._index
end
function UIRotateMenu2:_setIndex( curTmpIdx )
self._index = curTmpIdx
end
function UIRotateMenu2:callFunc()
self:rectify()
local curSp = self._itemT[self:_getIndex() + 1]
if curSp then
self.label:setString(curSp:getName())
end
end
function UIRotateMenu2:onPanelTouchBegan( touch,event )
-- cclog("UIRotateMenu2:onPanelTouchBegan")
if not self.isTouchInside(self,touch) then
return false
end
for k,v in pairs(self._itemT) do
v:stopAllActions()
end
return true
end
function UIRotateMenu2:onPanelTouchMoved( touch,event )
local deltaX = touch:getDelta().x
local curTmpIdx = self:transMoveLenToVar(deltaX)
self:_setIndex(curTmpIdx)
self:updatePos()
end
function UIRotateMenu2:onPanelTouchEnded( touch,event )
local deltaX = touch:getLocation().x - touch:getStartLocation().x
self:rectify(deltaX)
self:updatePosWithAni()
end
-- 将移动长度转为核心变量
function UIRotateMenu2:transMoveLenToVar(moveLen)
local cs = self:getContentSize()
return self._index - moveLen/(cs.width * self.ItemScrollFactor)
end
-- 将当前Idx转为曲线方程自变量
function UIRotateMenu2:transIdxToCurveFuncVar(idx)
return (idx - self._index) * self._unitAngle
end
function UIRotateMenu2:curveFuncSin(x,a,b) -- x:curAngle
return a + b * math.sin(x)
end
function UIRotateMenu2:curveFuncCos(x,a,b)
return a + b * math.cos(x)
end
function UIRotateMenu2:onEnter()
cclog("UIRotateMenu2:onEnter")
-- title
local label = cc.Label:createWithTTF(self.title(), "fonts/arial.ttf", 32)
self:addChild(label)
label:setAnchorPoint(cc.p(0.5, 0.5))
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) )
-- index label
label = cc.Label:createWithTTF("", "fonts/arial.ttf", 22)
label:setColor(cc.c3b(255,0,0))
self:addChild(label)
label:setAnchorPoint(cc.p(0.5, 0.5))
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 80) )
self.label = label
local ball = cc.Sprite:create("Images/moke1.jpg")
ball:setName("moke1")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke2.jpg")
ball:setName("moke2")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke3.jpg")
ball:setName("moke3")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke4.jpg")
ball:setName("moke4")
self:addMenuItem(ball)
ball = cc.Sprite:create("Images/moke5.jpg")
ball:setName("moke5")
self:addMenuItem(ball)
-- ball = cc.Sprite:create("Images/moke6.jpg")
-- self:addMenuItem(ball)
end
function UIRotateMenu2:onExit()
end
function UIRotateMenu2Main()
cclog("UIRotateMenu2Main")
local scene = cc.Scene:create()
local rotateMenu = UIRotateMenu2:create()
scene:addChild(rotateMenu)
scene:addChild(CreateBackMenuItem())
return scene
end
可以加入Cocos自带的各种Action实现更多的效果,如下:
修改代码
function UIRotateMenu2:updatePosWithAni()
for k,v in pairs(self._itemT) do
v:stopAllActions()
end
for k,v in pairs(self._itemT) do
local newpos = self:_getPos(k-1)
-- v:moveTo({time = self.AniDuration, x = newpos.x, y = newpos.y})
local action = cc.MoveTo:create(self.AniDuration, cc.p(newpos.x, newpos.y))
local move_ease_out = cc.EaseBounceOut:create(action)
v:runAction(move_ease_out)
v:scaleTo({time = self.AniDuration, scale = self:_getScale(k-1)})
v:fadeTo({time = self.AniDuration, opacity = self:_getOpacity(k-1)})
-- v:rotateTo({time = self.AniDuration, rotation = cc.vec3(0,self:_getRotation(k-1),0)})
v:setLocalZOrder(self:_getZorder(k-1))
end
local delayTimeAct = cc.DelayTime:create(self.AniDuration)
local sequence = cc.Sequence:create(delayTimeAct,cc.CallFunc:create(handler(self,self.callFunc)))
self:runAction(sequence)
end
1)在滑动时计算处于中间位置的Index;
2)确定采用何种曲线方程计算item的位置、尺度、旋转角度等属性;
3)基于item的index与中心位置的index,计算曲线函数自变量参数,从而进一步计算节点各属性。
至于其他过程,如中心index的矫正,一般无需修改。