-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Description
- cocos2d-x version: 3.17.1
- devices test on: N/A
- developing environments
- NDK version: N/A
- Xcode version: N/A
- VS version: N/A
- browser type and version: N/A
Steps to Reproduce:
- Add a ui::Slider node to the scene, and register for the percentage change event:
auto size = Director::getInstance()->getWinSize();
auto slider = ui::Slider::create();
slider->setTouchEnabled(true);
slider->loadBarTexture("cocosui/sliderTrack.png");
slider->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", "");
slider->loadProgressBarTexture("cocosui/sliderProgress.png");
slider->setPosition(Vec2(size.width / 2.0f, size.height / 2.0f));
slider->setPercent(52);
slider->addEventListener(CC_CALLBACK_2(SliderTest::sliderEvent, this));
addChild(slider, 999);
void SliderTest::sliderEvent(Ref *pSender, ui::Slider::EventType type)
{
if (type == Slider::EventType::ON_PERCENTAGE_CHANGED)
{
auto slider = dynamic_cast<ui::Slider*>(pSender);
CCLOG(">>> LineOptionIndex: %d", slider->getPercent());
}
}
- Run the test, and change the slider position, and you will notice in the console output that the percentage change event is sent many times, even if there is no change in the percentage value.
In UISlider.cpp, it should be updated to only broadcast that event if and only if the percentage value has changed, which would be literally what "ON_PERCENTAGE_CHANGED" means.
Also, it should be sent from inside the setPercent() method, and not from the onTouch*** handlers, because if setPercent() is called manually, a broadcast should still be sent out, in case there is a percentage changed handler registered to do something on any change in the value.
void Slider::setPercent(int percent)
{
if (percent > _maxPercent)
{
percent = _maxPercent;
}
if (percent < 0)
{
percent = 0;
}
// Only send event if value has changed
if (_percent != percent)
{
_percent = percent;
updateVisualSlider();
percentChangedEvent(EventType::ON_PERCENTAGE_CHANGED);
}
}
// New method to update the visual elements
void Slider::updateVisualSlider()
{
float res = 1.0 * _percent / _maxPercent;
float dis = _barLength * res;
_slidBallRenderer->setPosition(dis, _contentSize.height / 2.0f);
if (_scale9Enabled)
{
_progressBarRenderer->setPreferredSize(Size(dis,_contentSize.height));
}
else
{
Rect rect = _progressBarRenderer->getTextureRect();
rect.size.width = _progressBarTextureSize.width * res;
_progressBarRenderer->setTextureRect(rect, _progressBarRenderer->isTextureRectRotated(), rect.size);
}
}
There are 2 other methods named progressBarRendererScaleChangedWithSize() and barRendererScaleChangedWithSize() which call setPercent(_percent) to update the display. These should be changed to call updateVisualSlider() instead, since their purpose isn't to set a new percentage value, but simply to update the display of the slider.
Also, the touch handlers need to be updated to remove the event broadcast:
bool Slider::onTouchBegan(Touch *touch, Event *unusedEvent)
{
bool pass = Widget::onTouchBegan(touch, unusedEvent);
if (_hitted)
{
setPercent(getPercentWithBallPos(_touchBeganPosition));
percentChangedEvent(EventType::ON_SLIDEBALL_DOWN);
}
return pass;
}
void Slider::onTouchMoved(Touch *touch, Event* /*unusedEvent*/)
{
_touchMovePosition = touch->getLocation();
setPercent(getPercentWithBallPos(_touchMovePosition));
}
void Slider::onTouchEnded(Touch *touch, Event *unusedEvent)
{
Widget::onTouchEnded(touch, unusedEvent);
percentChangedEvent(EventType::ON_SLIDEBALL_UP);
}