Skip to content

ui::Slider sends ON_PERCENTAGE_CHANGED event even if no change in percentage #19555

@rh101

Description

@rh101
  • 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:

  1. 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());
    }
}
  1. 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);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions