quick-cocos2d-x 慣用CCScrollView滾動視圖


在用Cocos2d-x做遊戲開發時最常用的滾動視圖便是CCScrollViewCCScrollView的滾動是藉助于其內部容器的位置變動來達到的,再加以遮蓋/剪切便實現不可見的部分進行隱藏。藉助于CCScrollView,我們可以實現分頁效果,簡單的富文本,下拉式按鈕等。

創建一個CCScrollView式的滾動視圖,首先要創建一個容器,此容器可以必須是Node或其子孫類。如下: 

    self.layerContainer = display.newColorLayer(ccc4(10, 20, 30, 10))
	self.layerContainer:setTouchEnabled(true)
	self.layerContainer:setPosition(ccp(1, 0))
	self.layerContainer:setTouchSwallowEnabled(false)
	self.layerContainer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
		return self:onCellCallback(event.name, event.x, event.y)
	end)
self.widgetContainer = display.newSprite()	
	:align(display.LEFT_BOTTOM, 0, 0)	
	:addTo(self.layerContainer)

 

我們便創建了一個容器,此容器是一個帶有顏色的Layer,并設置了位置以及觸摸相關事件,還為其添加了一個孩子節點,并使觸摸事件綁定到了onCellCallback方法,此方法并沒有做過多的處理,只是簡單的記錄容器觸摸事件的起始和結果,如下:

function LLScrollView:onCellCallback(event, x, y)
	if event == "began" then
		self.bolTouchEnd = false
		return true
	elseif event == "ended" then
		self.bolTouchEnd = true
	end
end

這個方法可有可無,但為了實現下面的分頁就必不可少了,通過self.bolTouchEnd的標記,在後面的代碼中才能知道該何時處理,以及更好對CCScrollView進行滾動操作。下面我們來創建一個CCScrollView,并把剛才創建的Layer添加為其的容器:

	self.scrollView = CCScrollView:create()
    <span style="white-space:pre">	</span>self.scrollView:setContentSize(CCSizeMake(0, 0)) -- 設置內容大小
    <span style="white-space:pre">	</span>self.scrollView:setViewSize(CCSizeMake(self.scrollWidth, self.scrollHeight)) -- 設置可見大小
    <span style="white-space:pre">	</span>self.scrollView:setPosition(ccp(100, 100)) -- 設置位置
    <span style="white-space:pre">	</span>self.scrollView:setContainer(self.layerContainer) -- 設置容器
    <span style="white-space:pre">	</span>self.scrollView:setDirection(kCCScrollViewDirectionVertical) -- 設置滾動方向
	self.scrollView:setClippingToBounds(true) -- 設置剪切
	self.scrollView:setBounceable(true)  -- 設置彈性效果
	self.scrollView:setDelegate(this) -- 註冊為自身
	self:addChild(self.scrollView)

通過setContentSize制定CCScrollView的大小,當然這是可有可無的,其實并不是指定CCScrollView的大小,而是指定其容器的大小,一般我們都會在給容器添加數據的時候,再調整容器的大小;設置視圖的可見範圍就必不可少了,setViewSize方法為我們提供了設置視圖大小,設置視圖大小便指定了可見範圍,setClippingToBounds方法設置剪切,如果不設置,可見範圍的設置便成了虛設,通過setBounceable方法指定視圖滾動過程中是否能夠滾動,為了讓CCScrollView顯得不那麼僵硬,一般會設置為true;同時我們要設置滾動的方向setDirection,有3個方向,水平、豎直、雙向,setDelegate(this)指定註冊為自身。通過以上代碼我們便創建了一個完整的CCScrollView

為了實現滾動,還要為其添加滾動監聽事件,也就是寫個方法把其綁定到CCScrollView的滾動事件上,例如:

self.scrollView:registerScriptHandler(scrollView2DidScroll, CCScrollView.kScrollViewScroll)

這一行代碼就把方法scrollView2DidScroll綁定到了CCScrollView.kScrollViewScroll事件上,要做什麼處理工作便在scrollView2DidScroll方法中添加,比如我們要實現分頁,或滾動時實現一個item的滾動,如下:

	local function scrollView2DidScroll()
		if self.bolTouchEnd == true then
			self.bolTouchEnd = false
			local offy = self.layerContainer:getPositionY()
			local miny = self.scrollHeight-self.cellNums*self.cellHeight
			if offy < 0 and offy > miny then
				local item = -(math.abs(offy)%self.cellHeight)
				if item <= -self.cellHeight/2 then
					if offy < self.preOffy then
						item = offy-item-self.cellHeight 
					else
						item = offy-item-self.cellHeight
					end
				else
					item = offy-item
				end
				self.scrollView:setContentOffset(ccp(1, item), true)
			end
		end
	end

順便提一下,一些全局變量的定義在這裡:

	self.scrollTop = 208
	self.scrollHeight = 208
	self.scrollWidth = 152
	self.cellHeight = 52
	self.cellNums = 2

至於什麼意思,看到命名字段應該還是淺顯易懂的,就不一一解釋了,其中self.preOffy是記錄上一次CCScrollView的偏移量。分頁也很簡單,首先假定我們的ScrollView的偏移量都是負值,確實也是負值。由於CCScrollView會自動糾正第一項和最後一項的位置,所以在第一項和最後一項時我們不做處理,讓CCScrollView的內部方法去實現。如果CCScrollView的偏移量對一個item取余數,如果餘數大於item的一半我們就分頁,否則就歸位。代碼if offy < self.preOffy then是為了判定滾動方向是上還是下(我的這個CCScrollView的設置方向是豎直的),好了到此為止我們的完整的帶分頁的CCScrollView就實現了。

現在要對其添加數據,方便起見我又創建了一個類名稱為LLScrollItem,實現一個item的類,并為其添加了一個ON_TOUCH_EVENT的事件,完整代碼如下:

local LLScrollItem = class("LLScrollItem", function()
	return display.newNode()
end)
LLScrollItem.ON_TOUCH_EVENT = "on_touch_event"
function LLScrollItem:ctor(params)
	cc(self):addComponent("components.behavior.EventProtocol"):exportMethods()
	self.text = params.text
	local label = ui.newTTFLabel({
		text = params.text,
		font = "Arial",
		size = 20,
		})
	label:setTouchEnabled(true)
	label:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
		self:onTouch(event)
	end)
	local rect = {
		{0, 0},
		{150, 0},
		{150, 52},
		{0, 52},
		{0, 0}
	}
	local r, g, b, s = math.random(0, 255), math.random(0, 255), math.random(0, 255), math.random(0, 255)
	local layerColor = display.newColorLayer(ccc4(r, g, b, s)):addTo(self)
	:align(display.LEFT_BOTTOM, 0, 0)
	layerColor:setContentSize(CCSizeMake(150, 52))
	local polygon = display.newPolygon(rect, 1):addTo(layerColor)
	:align(display.LEFT_BOTTOM, 0, 0)
	polygon:setLineWidth(1)
	polygon:setLineColor(ccc4f(255, 0, 0, 255))
	label:addTo(polygon)
	label:align(display.CENTER, 75, 26)
	label:setColor(ccc3(255-r, 255-g, 255-b))
end
function LLScrollItem:onTouch(event)
	self:dispatchEvent({name=LLScrollItem.ON_TOUCH_EVENT, text = self.text})
end

return LLScrollItem

每一個item是一個有範圍界定有色層,并用一個Box包裹,并添加了一個獨一的文本,用來以後區別我們點擊了哪個item

利用上面的item類我們就可以為CCScrollView添加數據了:

	for i=1, self.cellNums do
		self.scrollTop = self.scrollTop - self.cellHeight
		local cell = LLScrollItem.new({text="ScrollItem: " .. i}):addTo(self.widgetContainer)
		:align(display.LEFT_BOTTOM, 0, self.scrollTop)

		cc.EventProxy.new(cell, cell)
			:addEventListener(cell.ON_TOUCH_EVENT, function(event)
				self.label:setString(event.text)
			end)
	end

因為容器內容變化了,所以要改變其大小,以便能夠完全承載所有數據;設置容器的位置是容器能夠達到的最低點,容器的孩子self.widgetContainer,其實是一個真正的承載數據的節點,我們在這裡要設置其能夠達到的最高高度。

我們之所以要給容器添加一個子節點,并所有數據都添加到其子節點上,是為應對動態增刪其數據內容的情況,并使CCScrollView的顯示正常。

我們再創建兩個控件,一個Label一個Button

	self.label = ui.newTTFLabel({
		text = "Hello, World", 
		size = 20,
		color = ccc3(163, 140, 14),
		align = ui.TEXT_ALIGN_CENTER
		})
    :pos(display.cx+100, display.cy+100)
    :addTo(self)
    self.button = cc.ui.UIPushButton.new({
    	disabled = "nil",
    	normal = "res/GreenScale9Block.png",
    	pressed = "res/PinkScale9Block.png",
    	})
    :align(display.CENTER, display.cx+100, display.cy-100)
    :addTo(self)
    :onButtonClicked(
    	function()
    		self:addItem()
    	end
    	)

這個Label就是上面所說的self.label,此Button是為了實現動態添加數據的功能,點擊Button就為CCScrollView添加數據,我們把其相應事件綁定到了addItem方法,此方法實現為:

function LLScrollView:addItem()
	self.scrollTop = self.scrollTop - self.cellHeight
	self.cellNums = self.cellNums+1
	local cell = LLScrollItem.new({text="ScrollItem: " .. self.cellNums}):addTo(self.widgetContainer)
	:align(display.LEFT_BOTTOM, 0, self.scrollTop)

	cc.EventProxy.new(cell, cell)
		:addEventListener(cell.ON_TOUCH_EVENT, function(event)
			self.label:setString(event.text)
		end)

	local h = self.cellNums*self.cellHeight
	if h < self.scrollHeight then
		h = self.scrollHeight
	end
	self.layerContainer:setContentSize(CCSizeMake(self.scrollWidth, h))
	self.widgetContainer:setPositionY(h-self.scrollHeight)
	self.layerContainer:setPositionY(self.scrollHeight-h)
	self.preOffy = self.layerContainer:getPositionY()
	local h1 = self.scrollHeight-h
	if h1 < 0 then h1 = 0 end
	self.layerContainer:setPositionY(h1)
end

同樣的,在添加完數據之後,一定要調整容器及其子節點的位置及大小,否則顯示出問題。到此位置我們已經實現了一個完整的能夠實現分頁、動態添加數據的CCScrollView,至於動態刪除,仿照動態添加自然也就出來了。

一個簡單的富文本,我們一樣可以實現,現只提示一個方法。我們可以把每一個圖片、文本當做一個item,然後從上到下、從左到右進行添加到CCScrollView當中,是不是就是一個簡單的富文本呢?我已經實現過,效果還可以,當然不能與PC上的富文本相提並論了,這只是一個簡單的富文本。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值