当前位置: 首页 > 工具软件 > UIListView > 使用案例 >

quick3.3 UIListview扩展应用

季俭
2023-12-01
--[[
    自定义滑动列表控件
    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", x = event.x, y = event.y}
    elseif "ended" == event.name then
        if self.bDrag_ then
            self.bDrag_ = false
            self:scrollAuto()
         -- self:autoFixScroll()
            self:callListener_{name = "ended", x = event.x, y = event.y}
 
            self:disableScrollBar()
        else
            self:callListener_{name = "clicked", x = event.x, 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,#self.items_ do
            item = self.items_[i] 
            local _x,_y = item:getPosition()

            bound = {x=_x-self.viewRect_.x,y=_y,width=_w,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, 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,
                      {x = disX, y = disY, time = 0.3,
                       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

 类似资料: