问题由来
一个排行榜列表,开始只加载10条数据。如果用户滑到底了,向服务器请求数据,收到数据后,往列表里加10条数据(是追加,不是清空列表再加载20条数据)。但问题是每次加入子项后,列表框跳到顶部去了。
解决方法
ListView里有这么个方法。
void jumpToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint);
第一个参数是item的序号,加进ListView的item是从0开始递增的。
第二个参数是相对于列表框大小的比率。比方说,Vec2(0.5,0.5)表示列表框的正中心。
第三个参数是item的锚点。
那么这个函数的作用就是,把序号为itemIndex的子项,以itemAnchorPoint为锚点,放到以列表框左下角为原点的坐标系里的点(列表框宽 乘 positionRatioInView.x, 列表框高 乘 positionRatioInView.y)那里去。
代码
bool HelloWorld::init()
{
if ( !cocos2d::Scene::init() )
{
return false;
}
auto visibleSize = cocos2d::Director::getInstance()->getVisibleSize();
auto origin = cocos2d::Director::getInstance()->getVisibleOrigin();
auto lsv = cocos2d::ui::ListView::create();
lsv->setContentSize(cocos2d::Size(300, 300));
lsv->setAnchorPoint(cocos2d::Vec2(0.5, 0.5));
lsv->setPosition(origin + cocos2d::Vec2(visibleSize / 2));
lsv->setBackGroundColor(cocos2d::Color3B::GRAY);
lsv->setBackGroundColorType(cocos2d::ui::Layout::BackGroundColorType::SOLID);
lsv->setDirection(cocos2d::ui::ScrollView::Direction::VERTICAL);
lsv->setGravity(cocos2d::ui::ListView::Gravity::CENTER_HORIZONTAL);
lsv->setBounceEnabled(true);
lsv->setScrollBarAutoHideEnabled(false);
lsv->setItemsMargin(10);
lsv->addEventListener((cocos2d::ui::ScrollView::ccScrollViewCallback)
CC_CALLBACK_2(HelloWorld::onEventScrollView, this));
addChild(lsv, 2, "lsv");
m_page = 1;//表示当前请求的是第几页数据
push10ItemsIntoListView();//假设第一页收到响应了,这不重要好吧
return true;
}
void HelloWorld::push10ItemsIntoListView()
{
cocos2d::log("push items into listview. current page = %d", m_page);
auto lsv = dynamic_cast<cocos2d::ui::ListView*>(this->getChildByName("lsv"));
for (int i = 0; i < 10; i++)
{
auto panel = cocos2d::ui::Layout::create();
panel->setContentSize(cocos2d::Size(250, 40));
panel->setBackGroundColor(cocos2d::Color3B::ORANGE);
panel->setBackGroundColorType(cocos2d::ui::Layout::BackGroundColorType::SOLID);
lsv->pushBackCustomItem(panel);
int n = (m_page - 1) * 10 + i;
auto txt = cocos2d::ui::Text::create(cocos2d::StringUtils::format("%d", n), "fonts/arial.ttf", 40);
txt->setPosition(cocos2d::Vec2(panel->getContentSize() / 2));
txt->setName("txt1");
panel->addChild(txt);
}
if (m_page > 1)
{
cocos2d::log("listview jump to item %ld", m_bottomWidgetIndex);
lsv->jumpToItem(m_bottomWidgetIndex, cocos2d::Vec2(0.5, 0), cocos2d::Vec2(0.5, 0));
}
}
void HelloWorld::onEventScrollView(cocos2d::Ref* pSender, cocos2d::ui::ScrollView::EventType type)
{
auto lsv = dynamic_cast<cocos2d::ui::ListView*>(pSender);
switch (type)
{
case cocos2d::ui::ScrollView::EventType::AUTOSCROLL_ENDED:
{
auto wgt_bottom = lsv->getBottommostItemInCurrentView();
m_bottomWidgetIndex = lsv->getIndex(wgt_bottom);
cocos2d::log("0 autoscroll ended. bottom widget's index = %ld", m_bottomWidgetIndex);
if (m_bottomWidgetIndex == m_page * 10 - 1)
{
cocos2d::log("1 listview reached bottom");
m_page++;
httpRequest(m_page);
}
}
break;
default:
break;
}
}
void HelloWorld::httpRequest(int page)
{
cocos2d::log("2 send request");
//假设这里的请求参数里需要用到page,代表请求第几页数据
const char* postData = "visitor=cocos2d&TestSuite=Extensions Test/NetworkTest";
auto request = new (std::nothrow) cocos2d::network::HttpRequest();
request->setUrl("http://httpbin.org/post");
request->setRequestType(cocos2d::network::HttpRequest::Type::POST);
request->setResponseCallback(CC_CALLBACK_2(HelloWorld::onHttpRequestCompleted, this));
request->setRequestData(postData, strlen(postData));
cocos2d::network::HttpClient::getInstance()->send(request);
request->release();
}
void HelloWorld::onHttpRequestCompleted(cocos2d::network::HttpClient* client, cocos2d::network::HttpResponse* response)
{
cocos2d::log("3 recv response");
if (!response)
{
return;
}
if (!response->isSucceed())
{
cocos2d::log("code=%ld buffer=%s", response->getResponseCode(), response->getErrorBuffer());
return;
}
std::vector<char>* buffer = response->getResponseData();
//假设这里返回的是10条需要加入列表框的数据
auto lsv = dynamic_cast<cocos2d::ui::ListView*>(this->getChildByName("lsv"));
push10ItemsIntoListView();
}
方法的不足
jump到某个item,还是会闪一下,用户体验不好。
参考
cocos2dx使用listView->scrollToItem在滚动的中途触发滚动会乱套
ListView not aligning magnetically like expected with scrolltoitem

网友评论