按照惯例先发上效果图:
正文:
一说起滚动效果大家可能会联想到Cocos2d-x给我们提供的ScrollView。我一开始也是打算用ScrollView来实现的,但是用着用着发现出现了各种莫名其妙的错误,所以只好自己重新写一个Node,通过onTouchBegan和onTouhMoved两个事件回调来实现滚动的效果。
GridView使用说明:
1.利用GridView::create(int row,int column)来创建一个GridView,row和column分别指定行数和列数。注意这里的行数是指可见的行数
2.通过GridView::addItem(Node* node)来向GridView里面添加元素
GridView实现思路:
1.创建的时候指定行数和列数
2.GridView里面新建一个Node(visibleNode)用于保存所有的item(以后实现滚动的时候方便点)
3.通过addItem进GridView时,计算出item的位置(x,y)
4.接受触摸事件
5.计算触摸的偏移量,visibleNode移动相应的距离
6.一头一尾的触摸要稍作判断(即不能上方出现空白或全空白)
7.添加遮罩层
核心代码解析:
1、添加Item
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
41
42
43
44
45
46
47
48
49
50
|
void
GridView::addItem(Node*item){
if
(getItemSize()==0){<spanstyle=
"white-space:pre"
></span>
//如果是第一个Item(则以这个item为标准)
m_visible_node=Node::create();<spanstyle=
"white-space:pre"
></span>
//visibleNode用于保存所有的item
m_visible_node->setAnchorPoint(Point(0,0));
m_visible_node_posy_max=0;<spanstyle=
"white-space:pre"
></span>
//m_visible_posy_max表示现在最大能移上去多少(对应于尾的判断)
m_item_width=item->getContentSize().width;<spanstyle=
"white-space:pre"
></span>
//利用第一个Item来确定标准
m_item_height=item->getContentSize().height;
this
->setContentSize(
Size(m_item_width*m_column_num,m_item_height*m_row_num)
);
m_visible_node->setContentSize(
Size(m_item_width*m_column_num,m_item_height*m_row_num)
);
ClippingNode*cliper=ClippingNode::create();<spanstyle=
"white-space:pre"
></span>
//遮罩层
DrawNode*drawNode=DrawNode::create();
Pointpoints[]={Point(getPosition()),
Point(getPositionX(),getPositionY()+m_row_num*m_item_height),
Point(getPositionX()+m_column_num*m_item_width,
Point(getPositionX()+m_column_num*m_item_width,getPositionY())};
drawNode->drawpolygon(points,4,Color4F(0,1),0));
LayerColor*stencil=LayerColor::create(Color4B(0x00,0x00,0xC0),
this
->getContentSize().width,
this
->getContentSize().height);
stencil->setAnchorPoint(Point(0,0));
cliper->setStencil(stencil);
cliper->addChild(m_visible_node);
this
->addChild(cliper);
scrollbar=ScrollBar::create(m_row_num*m_item_height);<spanstyle=
"white-space:pre"
></span>
//滚动条(下面会讲到可以先跳过)
scrollbar->setPosition(m_item_width*m_column_num,0);
this
->addChild(scrollbar);
}
item->setAnchorPoint(Point(0,1));
int
index=getItemSize()+1;
float
x=(index-1)%m_column_num*m_item_width;<spanstyle=
"white-space:pre"
></span>
//计算出item的x,y
float
y=m_item_height*m_row_num-((index-1)/m_column_num*m_item_height);
item->setPosition(Point(x,y));
int
cur_max_row=(index-1)/m_column_num+1;
if
(cur_max_row>m_row_num){<spanstyle=
"white-space:pre"
></span>
//如果当前最大行数超过可见行
m_visible_node_posy_max=(cur_max_row-m_row_num)*m_item_height;<spanstyle=
"white-space:pre"
></span>
//设置最大能移上去多少
scrollbar->setButtonSize(m_row_num*1.0/cur_max_row);<spanstyle=
"white-space:pre"
></span>
}
m_visible_node->addChild(item);<spanstyle=
"white-space:pre"
></span>
//添加到visibleNode里面
m_items.insert(index,item);
}
|
2、触摸事件
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
|
bool
GridView::onTouchBegan(Touch*pTouch,Event*pEvent){
Pointp=Director::getInstance()->convertToGL(pTouch->getLocationInView());
if
(
this
->getBoundingBox().containsPoint(p)){<spanstyle=
"white-space:pre"
></span>
//判断是否触摸到
move_began=p;
return
true
;
}
return
false
;
}
void
GridView::onTouchMoved(Touch*pTouch,Event*pEvent){
cclOG(
"TouchMoved"
);
move_ing=Director::getInstance()->convertToGL(pTouch->getLocationInView());
if
(!
this
->getBoundingBox().containsPoint(move_ing))
return
;
float
offset_y=move_ing.y-move_began.y;
//计算出偏移量
cclOG(
"move_y:%f"
,offset_y);
m_visible_node->setPositionY(m_visible_node->getPositionY()+offset_y);
//visibleNode移动相应的偏移量
if
(m_visible_node->getPositionY()<0){<spanstyle=
"white-space:pre"
></span>
//头的判断(因为整个GridView的AnchorPoint是(0,0))
m_visible_node->setPositionY(0);
}
if
(m_visible_node->getPositionY()>m_visible_node_posy_max){
//尾的判断。前面已经计算出最大可以上移的高度
m_visible_node->setPositionY(m_visible_node_posy_max);
}
if
(m_visible_node_posy_max>0){<spanstyle=
"white-space:pre"
></span>
//这里主要是用在滚动条
float
delta_y=m_visible_node->getPositionY();
float
percent=delta_y/m_visible_node_posy_max;
scrollbar->setButtonPos(percent);
}
move_began=move_ing;
}
|
3、滚动条
实现思路:
1)滚动条的大小由可见行数决定:滚动条高度=可见行数*每个Item的高度
2)滚动Button的大小由当前最大行数和可见行数决定:滚动Button的大小=可见行/最大行 * 滚动条高度
3)滚动条的位置由GridView当前位置和GridView最大可以上升的位置、滚动Button大小和滚动条大小决定
可以这样理解:
GridView上升高度/最大可以上升高度 = Button下降高度/Button最大可以下降高度
其中,GridView的上升高度和最大上升高度可以直接获取,Button的最大下降高度= 滚动条大小-Button大小
因此,可以求出Button的下降高度。也就可以确定Button的位置
4、GridView主要用途
GridView可以用来做背包视图,或者一个简单的listView(需要设置列数为1)
最后,附上源码:注意要把那两个图片放到resource文件夹里面哦
源码下载:带滚动的表格GridView