前言:
按照惯例先发上效果图:
正文:
先来吐槽几句,一说起滚动效果大家可能会联想到Cocos2dx给我们提供的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
void GridView::addItem(Node* item){ if(getItemSize() == 0){<span style="white-space:pre"> </span>//如果是第一个Item(则以这个item为标准) m_visible_node = Node::create();<span style="white-space:pre"> </span>//visibleNode用于保存所有的item m_visible_node->setAnchorPoint(Point(0,0)); m_visible_node_posy_max = 0;<span style="white-space:pre"> </span>//m_visible_posy_max表示现在最大能移上去多少(对应于尾的判断) m_item_width = item->getContentSize().width;<span style="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();<span style="white-space:pre"> </span>//遮罩层 DrawNode* drawNode = DrawNode::create(); Point points[] = {Point(getPosition()), Point(getPositionX(),getPositionY()+m_row_num*m_item_height), Point(getPositionX()+m_column_num*m_item_width,getPositionY()+m_row_num*m_item_height), Point(getPositionX()+m_column_num*m_item_width,getPositionY())}; drawNode->drawPolygon(points,4,Color4F(0,0,0,1),0,Color4F(0,0,0,0)); LayerColor* stencil = LayerColor::create(Color4B(0x00, 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);<span style="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;<span style="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){<span style="white-space:pre"> </span>//如果当前最大行数超过可见行 m_visible_node_posy_max = (cur_max_row-m_row_num)*m_item_height;<span style="white-space:pre"> </span>//设置最大能移上去多少 scrollbar->setButtonSize(m_row_num*1.0/cur_max_row);<span style="white-space:pre"> </span> } m_visible_node->addChild(item);<span style="white-space:pre"> </span>//添加到visibleNode里面 m_items.insert(index,item); }
2、触摸事件
bool GridView::onTouchBegan(Touch* pTouch,Event* pEvent){ Point p = Director::getInstance()->convertToGL(pTouch->getLocationInView()); if(this->getBoundingBox().containsPoint(p)){<span style="white-space:pre"> </span>//判断是否触摸到 move_began = p; return true; } return false; } void GridView::onTouchMoved(Touch* pTouch,Event* pEvent){ CCLOG("Touch Moved"); 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){<span style="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){<span style="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文件夹里面哦