--[[ 自定义滑动列表控件 1.支持UIListView所有功能 2.额外增加让条目滑动后始终显示全部功能 3.额外增加当条目滑过指定区域时发生放大缩小变化,调用enableAreaChange()方法即可开启 author:chjh0540237 ]] local c = cc local UIScrollView = cc.ui.UIScrollView local CustomListView = class("CustomListView",cc.ui.UIListView) --设置滑动中指定区域内有放大缩小过渡变化 --_areaParam:{point=xxx,areaValue=xxx,scaleRate=xxx} --若滑动列表为横向,则 point 代表X轴的该点以areaValue 为 区域的中心点来作条目在该区域变化判断 --若滑动列表为竖向,则 point 代表Y轴的该点以areaValue 为 区域的中心点来作条目在该区域变化判断 --scaleRate滑动条目缩放比例,可以不填 --不传参数则取当前列表大小中心位置 function CustomListView:enableAreaChange(_areaParam) self.m_isAreaEnabled_ = true self.m_area_ = _areaParam self.m_rate_ = 1 return self end function CustomListView:autoFixScroll() if UIScrollView.DIRECTION_VERTICAL == self.direction then self:autoFixY() else self:autoFixX() end end --横向滑动时,使条目显示全 function CustomListView:autoFixX() local item,pos = self:getFirstVisibleItem() local bound = item:getBoundingBox() local nodePoint = self.container:convertToWorldSpace( c.p(bound.x + bound.width/2,bound.y)) local index if c.rectContainsPoint(self.viewRect_,nodePoint) then index = pos else index = pos + 1 end local toItem = self.items_[index] bound = toItem:getBoundingBox() self:scrollToPos(-bound.x + self.viewRect_.x,0) end --竖向滑动时,使条目显示全 function CustomListView:autoFixY() local item,pos = self:getFirstVisibleItem() local bound = item:getBoundingBox() local nodePoint = self.container:convertToWorldSpace( c.p(bound.x,bound.y+bound.height*0.5)) local index if c.rectContainsPoint(self.viewRect_,nodePoint) then index = pos else index = pos + 1 end local toItem = self.items_[index] bound = toItem:getBoundingBox() self:scrollToPos(0,-bound.y-bound.height+self.viewRect_.height+self.viewRect_.y) end function CustomListView:getFirstVisibleItem() for i=1,#self.items_ do if self:isItemInViewRect(self.items_[i]) then return self.items_[i],i end end end function CustomListView:scrollToPos(x,y) -- local scrollLength = c.pGetLength(c.pSub(c.p(x,y),self.position_)) self.position_ = c.p(x,y) local action = c.MoveTo:create(0.5,self.position_) self.scrollNode:runAction(transition.sequence({c.EaseExponentialOut:create(action),c.CallFunc:create(function() if self.m_isAreaEnabled_ then local _item,_index = self:getScaledItem_() self:callListener_{name = "scrollStop",item=_item,pos=_index} end end) })) self:scrollChange(x,y) -- self.scrollNode:runAction(c.EaseElasticOut:create(action)) end function CustomListView:getAllItem() return self.items_ end function CustomListView:getFirstItem() return self.items_[1] end function CustomListView:getLastItem() return self.items_[#self.items_] end -- override function CustomListView:onTouch_(event) if "began" == event.name and not self:isTouchInViewRect(event) then printInfo("UIScrollView - touch didn't in viewRect") return false end if "began" == event.name and self.touchOnContent then local cascadeBound = self.scrollNode:getCascadeBoundingBox() if not cc.rectContainsPoint(cascadeBound,cc.p(event.x,event.y)) then return false end end if "began" == event.name then self.prevX_ = event.x self.prevY_ = event.y self.bDrag_ = false local x,y = self.scrollNode:getPosition() self.position_ = {x = x,y = y} transition.stopTarget(self.scrollNode) self:callListener_{name = "began",x = event.x,y = event.y} self:enableScrollBar() -- self:changeViewRectToNodeSpaceIf() self.scaleToWorldSpace_ = self:scaleToParent_() return true elseif "moved" == event.name then if self:isShake(event) then return end self.bDrag_ = true self.speed.x = event.x - event.prevX self.speed.y = event.y - event.prevY if self.direction == UIScrollView.DIRECTION_VERTICAL then self.speed.x = 0 elseif self.direction == UIScrollView.DIRECTION_HORIZONTAL then self.speed.y = 0 else -- do nothing end self:scrollBy(self.speed.x,self.speed.y) self:scrollChange() self:callListener_{name = "moved",y = event.y} elseif "ended" == event.name then if self.bDrag_ then self.bDrag_ = false self:scrollAuto() -- self:autoFixScroll() self:callListener_{name = "ended",y = event.y} self:disableScrollBar() else self:callListener_{name = "clicked",y = event.y} end end end --滚动变化 function CustomListView:scrollChange(x,y) if not self.m_isAreaEnabled_ then return end local scrollX,scrollY = x or self:getScrollNode():getPositionX(),y or self:getScrollNode():getPositionY() -- printf("当前正在滚动 scrollNode.pos=(%f,%f)",scrollX,scrollY) local line -- = self.viewRect_.width*0.5 local min,max -- = lineX-80,lineX+80 local bound local _w,_h = self.items_[1]:getItemSize() local item if UIScrollView.DIRECTION_VERTICAL == self.direction then if self.m_area_ then line = self.m_area_.point or self.viewRect_.height*0.5 _h = self.m_area_.areaValue or _h self.m_rate_ = self.m_area_.scaleRate or 1 else line = self.viewRect_.height*0.5 end min,max = line-_h*0.5,line+_h*0.5 for i=1,#self.items_ do item = self.items_[i] local _x,_y = item:getPosition() bound = {x=_x,y=_y-self.viewRect_.y,width=_w,height=_h} local cury = bound.y+bound.height*0.5+scrollY if cury>min and cury<=line then self.items_[i]:getContent():setScale(cury/min*self.m_rate_) item._isScaled = true item:setLocalZOrder(1) elseif cury>line and cury<max then self.items_[i]:getContent():setScale((line-(cury-line))/min*self.m_rate_) item._isScaled = true item:setLocalZOrder(1) else self.items_[i]:getContent():setScale(1) item._isScaled = false item:setLocalZOrder(0) end end else if self.m_area_ then line = self.m_area_.point or self.viewRect_.width*0.5 _w = self.m_area_.areaValue or _w self.m_rate_ = self.m_area_.scaleRate or 1 else line = self.viewRect_.width*0.5 end min,max = line-_w*0.5,line+_w*0.5 for i=1,_y = item:getPosition() bound = {x=_x-self.viewRect_.x,y=_y,height=_h} local curX = bound.x+bound.width*0.5+scrollX if curX>min and curX<=line then self.items_[i]:getContent():setScale(curX/min*self.m_rate_) item._isScaled = true item:setLocalZOrder(1) elseif curX>line and curX<max then self.items_[i]:getContent():setScale((line-(curX-line))/min*self.m_rate_) item._isScaled = true item:setLocalZOrder(1) else self.items_[i]:getContent():setScale(1) item._isScaled = false item:setLocalZOrder(0) end end end end function CustomListView:scrollAuto() local status = self:twiningScroll() if status == "normal" then self:elasticScroll(true) elseif status == "sideShow" then self:elasticScroll(false) end end function CustomListView:twiningScroll() if self:isSideShow() then -- printInfo("UIScrollView - side is show,so elastic scroll") return "sideShow" end if math.abs(self.speed.x) < 10 and math.abs(self.speed.y) < 10 then -- printInfo("#DEBUG,UIScrollView - isn't twinking scroll:" -- .. self.speed.x .. " " .. self.speed.y) return "normal" end local disX,disY = self:moveXY(0,self.speed.x*6,self.speed.y*6) transition.moveBy(self.scrollNode,{x = disX,y = disY,time = 0.3,easing = "sineOut",onComplete = function() self:elasticScroll(true) end}) end function CustomListView:elasticScroll(fix) local cascadeBound = self:getScrollNodeRect() local disX,disY = 0,0 local viewRect = self:getViewRectInWorldSpace() -- dump(cascadeBound,"UIScrollView - cascBoundingBox:") -- dump(viewRect,"UIScrollView - viewRect:") if cascadeBound.width < viewRect.width then disX = viewRect.x - cascadeBound.x else if cascadeBound.x > viewRect.x then disX = viewRect.x - cascadeBound.x elseif cascadeBound.x + cascadeBound.width < viewRect.x + viewRect.width then disX = viewRect.x + viewRect.width - cascadeBound.x - cascadeBound.width end end if cascadeBound.height < viewRect.height then disY = viewRect.y + viewRect.height - cascadeBound.y - cascadeBound.height else if cascadeBound.y > viewRect.y then disY = viewRect.y - cascadeBound.y elseif cascadeBound.y + cascadeBound.height < viewRect.y + viewRect.height then disY = viewRect.y + viewRect.height - cascadeBound.y - cascadeBound.height end end if 0 == disX and 0 == disY then if fix then self:autoFixScroll() end return end self:scrollChange(self.scrollNode:getPositionX()+disX,self.scrollNode:getPositionY()+disY) transition.moveBy(self.scrollNode,easing = "backout",onComplete = function() self:callListener_{name = "scrollEnd"} -- self:callListener_{name = "scrollStop"} end}) end function CustomListView:getScaledItem_() for i=1,#self.items_ do if self.items_[i]._isScaled then return self.items_[i],i end end return nil end return CustomListView