CCScrollView的滾動是藉助於其內部容器的位置變動來達到的,再加以遮蓋/剪切便實現不可見的部分進行隱藏。
藉助於CCScrollView,我們可以實現分頁效果,簡單的富文本,下拉式按鈕等。
創建一個CCScrollView式的滾動視圖,首先要創建一個容器,此容器可以必須是Node或其子孫類。如下:
1
2
3
4
5
6
7
8
9
10
|
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方法,此方法並沒有做過多的處理,只是簡單的記錄容器觸摸事件的起始和結果,如下:
1
2
3
4
5
6
7
8
|
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添加爲其的容器:
1
2
3
4
5
6
7
8
9
10
|
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的滾動事件上,例如:
1
|
self.scrollView:registerScriptHandler(scrollView2DidScroll, CCScrollView.kScrollViewScroll) |
這一行代碼就把方法scrollView2DidScroll綁定到了CCScrollView.kScrollViewScroll事件上,要做什麼處理工作便在scrollView2DidScroll方法中添加,比如我們要實現分頁,或滾動時實現一個item的滾動,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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 |
順便提一下,一些全局變量的定義在這裏:
1
2
3
4
5
|
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的事件,完整代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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添加數據了:
1
2
3
4
5
6
7
8
9
10
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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方法,此方法實現爲:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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,至於動態刪除,仿照動態添加自然也就出來了。