tableview作爲一種UI是非常實用的,它可以顯示多列元素,並且可以通過滑動來即時加載元素,常用的就是遊戲中的物品欄,物品欄在各類遊戲中都佔有很重要的地位,卡牌遊戲中卡牌的整理,RPG中的物品欄等,這些都需要滑動換頁,元素點擊的要素,而tableview在功能上能夠完美的實現這個,接下來以實際的卡牌的整理界面來介紹tableview
一,要使用tableview首先需要繼承cocos2dx中tableviewdatasource和TableViewDelegate兩個類,並重載其中的四個方法
virtual TableViewCell* tableCellAtIndex(TableView *table,ssize_t idx);
//返回單元格個數,指的是行數,不是指行內總元素的個數
virtual ssize_t numberOfCellsInTableView(TableView *table);
//根據index設置單元格大小,同樣指每行的size
virtual Size tableCellSizeForIndex(TableView *tabe,ssize_t idx);
//cell中的元素顯示,即每行中要顯示的元素都是在這個函數中完成載入的
virtual void tableCellTouched(TableView *table ,TableViewCell *cell);
//cell的點擊事件,即每行的點擊事件
四個方法的重載如下:
//這裏需要使用dequeuecell來獲得cell,如果直接在內部創建cell會導致cell被重複創建,元素的顯示會變異常,需要注意僅在獲得的cell爲空的前提下才創建cell,否則只需改變
原有cell中的元素即可,
TableViewCell* CardSelectScene::tableCellAtIndex(TableView *table,ssize_t idx){
TableViewCell *cell=table->dequeueCell();
auto barray=Array::create();
int index=idx*3;
int indexfor=0;
int length=0;
if(table->getTag()==0){
barray=array;
}else if(table->getTag()==1){
barray=sarray;
}
if(barray!=NULL){
if(barray->count()-index<3){
length=barray->count()-index;
}else{
length=3;
}
if(!cell){
cell=new TableViewCell();
cell->autorelease();
}else{
cell->removeAllChildren();
}
for(int m=0;m<length;m++){
Dictionary* str=((Dictionary*)array->objectAtIndex(index+m));
custombutton *item=custombutton::createLayer(str);
if(item!=NULL){
item->setAnchorPoint(Point::ZERO);
//item->setScale(0.6);
indexfor=index+m;
item->setTag(index+m);
item->setPosition(Point(150*m,0));
item->setTouchEnabled(true);
item->setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
cell->addChild(item);
}
}
}
return cell;
//idx爲行號
}
//返回單元格個數
ssize_t CardSelectScene::numberOfCellsInTableView(TableView *table){
if(table->getTag()==0){
if(array->count()!=0){
if(array->count()<=3){
return 1;
}else{
return 1+array->count()/3;
}
}else{
return 2;
}
}else if(table->getTag()==1){
if(sarray==NULL){
return 0;
}else{
if(sarray->count()!=0){
if(sarray->count()<=3){
return 1;
}else{
return 1+sarray->count()/3;
}
}else{
return 2;
}
}
}
}
//根據index設置單元格大小
Size CardSelectScene::tableCellSizeForIndex(TableView *table,ssize_t idx){
return Size(434,260);
}
void CardSelectScene::tableCellTouched(TableView *table ,TableViewCell *cell){
CCLOG("cell touched at index: %ld", cell->getIdx());
}
三,元素在cell中的點擊
如果在cell中添加的元素含有menu類的控件時,會發現tableview會無法進行拖動,這是因爲響應優先級的問題,這個問題會在之後詳細介紹,今天要介紹的是元素的點擊,因爲實際點擊時通過touch指針獲取的點擊位置是世界座標,並不是cell內部的相對座標,而通過調試會發現,cell內部的座標全是相對於該cell的相對座標,再加上cocos2dx中通過dispatcher下發各種消息時會將消息均等的發送給所有此時在tableview界面上的元素,這樣實際用getBoundingBox()來判斷是否在元素範圍內是很蛋疼的,所以這裏採用一個折中的方案,先獲得點擊的是哪個cell,不是這個cell就不管,是在該cell中再繼續判斷,獲取點擊cell的位置如下,因爲對於tableview來說其cell的offset也是相對的,並且很蛋疼的是它還是個負值,以260爲高度,個數爲15個的tableview來說,最上面的0號cell,它的位置其實是(0,-3900)~(0,-3640)之間,所以才需要採用下面的方式來獲取點擊位置
auto locationworld =touch->getLocation();
auto offset=table->getContentOffset();
auto distance=locationworld.y-offset.y;//獲得相對座標,垂直顯示時的獲取方法
auto index=maxsize-(int)(distance/260)-1;//獲取點擊的cell的index,這裏260是每行cell的高度,maxsize就是tableview總的cell個數,
獲得點擊行數後就是內部判斷了
//判斷如果點擊位置是在上部時
if(cell->getIdx()%2==0){
if(locationworld.y>260){
Point location=Point(locationworld.x,locationworld.y-260);
if(this->getBoundingBox().containsPoint(location)){
log("m_power is %d",this->m_power);
return true;
}else{
return false;
}
}else{
Point location=Point(locationworld.x,locationworld.y);
if(this->getBoundingBox().containsPoint(location)){
log("m_power is %d",this->m_power);
return true;
}else{
return false;
}
}
//判斷是在下部時
}else if(cell->getIdx()%2==1){
Point location=Point(locationworld.x,locationworld.y);
if(this->getBoundingBox().containsPoint(location)){
log("m_power is %d",this->m_power);
return true;
}else{
return false;
}
}
效果圖如下,效果還算不錯