Editbox on IOS does not work correctly

Hi Guys,
I created a editbox, it work ok on android, but not ok on IOS.
Here is my code:

   _txtcamnhan = EditBox::create(Size(600, 200), ui::Scale9Sprite::create("images/bg.png"));
_txtcamnhan->setFontName("Arial.ttf");
_txtcamnhan->setFontSize(25);
_txtcamnhan->setFontColor(Color3B::BLACK);
_txtcamnhan->setPlaceHolder("Cam nhan");
_txtcamnhan->setPlaceholderFontColor(Color3B::GRAY);
_txtcamnhan->setPlaceholderFontSize(25);
_txtcamnhan->setInputMode(EditBox::InputMode::ANY);
_txtcamnhan->setInputFlag(EditBox::InputFlag::SENSITIVE);

The problem is, when this editbox is focused, the font size is so big, when the edited lose focus, everything came normal. You can see in the picture
On focus, begin edit


after editing

Can someone help me,many thanks.

@grimfate can you help me.

What I Discovered
cocos uses a cocos Label to display the text for the EditBox when you are not editing it. When you are editing it, it will hide the Label and start using a UITextField. (UITextField is an iOS control, which will be something else for Android. This will be why you are getting different results on Android and iOS.) It will switch back to the Label when you have finished editing.

When you set the font name or the font size, the code ends up at setNativeFont in UIEditBoxImpl-ios.mm. It will then call constructFont. constructFont tries to create a UIFont using the font name you provided, and if it fails it will return null. If constructFont returns null, then setNativeFont will skip changing the font for the UITextField. That means the font for editing text will neither update its style nor its size if your font name cannot be found.

Basic Explanation
Basically, I think iOS cannot find your font name. You can test this by changing your font name to something else, such as Helvetica, and it should be working fine.

It’s a bug in cocos. Whenever you change the font size, it will do so by creating a UIFont using both your font name and font size. If iOS cannot find your your font name, the UIFont will return null and the code will skip changing the font. So if you set a font name that iOS cannot find, you will never be able to change the size of the font because the invalid font name will always cause it to fail.

Because cocos uses its own Label for displaying the text normally and the system control for editing text, cocos will handle changing the font differently for both of them, which is why the 2 have different sizes for you.

Solutions

  • First, make sure you are using the latest version of cocos. It may have been fixed since whatever version you are on, if you are not using the latest version.
  • It seems like it doesn’t work because iOS can’t find your font, so the best solution is to find out why that is. I tried using my own custom font that cocos can display, but it still fails, so there may be steps you have to take beyond what cocos needs for using font. You may need to see if there is some specific way to add custom font so that iOS controls can use them.
  • Next option would be to use a different font that will work. I guess you would want to look up what the system fonts are and use one of them.
  • A worse solution is to set your font size before your font name or don’t set a font name at all. The font size doesn’t change because your font name cannot be found. If you set your font size before your font name then the size change will work because the invalid font name has not been set yet. This is not a great solution because your EditBox will have a different font style when editing and when not editing if you set a font name that cocos can find, but iOS cannot.
  • A bad solution would be to fix the cocos code yourself. My solution would be that if the font fails then just use the default font and the font size you specified. This is a “bad solution” because it involves changing cocos code and because your EditLabel will have different font when editing and when not editing.

EDIT
I have downloaded cocos2d-x v3.12 and it appears they have fixed this bug. I haven’t tested your code on it, but I inspected the cocos code that was causing this issue and it has been changed to something that should work. I don’t know if it will fix the issue with the UITextField not being able to find your font, but at least it will allow you to change the size of it.

1 Like

Thank you so much. you help me much more. currently, i use v 3.11, i will download v3.12 and try. Thank you again.

@grimfate
hi, one more time i bother you. i got a problem with RichText,

I try to create a richtext with url. something as test project. It’ work ok.
But now, i trying to create a modal layer, then i want to show this richtext on it. But when click on url, nothing happen.

this i the code i create Modal layer:

bool ModalLayer::init()
{
	if (!LayerColor::initWithColor(Color4B(0, 0, 0, 120)))
	{
		return false;
	}
	this->ignoreAnchorPointForPosition(false);

	auto touchListener = EventListenerTouchOneByOne::create();
	touchListener->setSwallowTouches(true); // i need this for modal purpose. prevent user from click on other layer.
	
	touchListener->onTouchBegan = CC_CALLBACK_2(ModalLayer::onTouchBegan, this);
	touchListener->onTouchEnded = CC_CALLBACK_2(ModalLayer::onTouchEnded, this);
	touchListener->onTouchMoved = CC_CALLBACK_2(ModalLayer::onTouchMoved, this);
	touchListener->onTouchCancelled = CC_CALLBACK_2(ModalLayer::onTouchCancelled, this);

	_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
	return true;
}

bool ModalLayer::onTouchBegan(Touch* touch, Event* event)
{
	auto localtouch = touch->getLocation();
	if (this->boundingBox().containsPoint(localtouch))
		return true;
	return false;
}
void ModalLayer::onTouchEnded(Touch* touch, Event* event)
{
	
}
void ModalLayer::onTouchMoved(Touch* touch, Event* event)
{

}
void ModalLayer::onTouchCancelled(Touch* touch, Event* event)
{
}

then, i create a richtext on it:

auto wait = ModalLayer::create();
auto message = cocos2d::ui::RichText::createWithXML("<font face='font.ttf' size=\"20\" color=\"#000000\"> And this link will redirect you to google: <a href='http://www.google.com'>Click here </a></font>");
	
	message->ignoreContentAdaptWithSize(false);
	message->setContentSize(Size(500,400));
	message->setPosition(Director::getInstance()->getVisibleSize()/2);
	wait->addChild(message,10);

as i research, both modallayer with richtext use : _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this); to capture event.
So when click on this, modal has swallow event. So click event on richtext do not happen.

So, how to priority event on richtext? can you help me.
thank you so much!

I’m having the same issue with RichText Input. This is about as simple and clear as I can make it:

  auto visibleSize = Director::getInstance()->getVisibleSize();
  auto size = Size(150.0f, visibleSize.height);

  auto rt1 = ui::RichText::create();
  rt1->ignoreContentAdaptWithSize(false);
  rt1->setContentSize(size);
  rt1->setPositionType(ui::Widget::PositionType::PERCENT);
  rt1->setPositionPercent(Vec2(0.25f, 0.5f));
  rt1->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  rt1->setOpenUrlHandler([](std::string url){
    if(url == "hit_here") {
      static int i1 = 0;
      CCLOG("Hit Left: %d", i1++);
    }
  });
 
  auto layout = ui::Layout::create();
  layout->setContentSize(size);
  layout->setPositionType(ui::Widget::PositionType::PERCENT);
  layout->setPositionPercent(Vec2(0.75f, 0.5f));
  layout->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  
  // Comment out this line and the input will be detected correctly on rt2
  layout->setTouchEnabled(true);

  auto rt2 = ui::RichText::create();
  rt2->ignoreContentAdaptWithSize(false);
  rt2->setContentSize(layout->getContentSize());
  rt2->setPositionType(ui::Widget::PositionType::PERCENT);
  rt2->setPositionPercent(Vec2::ANCHOR_MIDDLE);
  rt2->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  rt2->setOpenUrlHandler([](std::string url){
    if(url == "hit_here") {
      static int i2 = 0;
      CCLOG("Hit Right: %d", i2++);
    }
  });
  
  layout->addChild(rt2);
  addChild(layout);
  addChild(rt1);

  rt1->pushBackElement(ui::RichElementText::create(1, Color3B::GRAY, 255, "This will detect clicks.  ", "fonts/arial.ttf", 30));
  rt1->pushBackElement(ui::RichElementText::create(2, Color3B::RED, 255, "Click Here", "fonts/arial.ttf", 30, ui::RichElementText::URL_FLAG, "hit_here"));

  rt2->pushBackElement(ui::RichElementText::create(1, Color3B::GRAY, 255, "This will not detect clicks.  ", "fonts/arial.ttf", 30));
  rt2->pushBackElement(ui::RichElementText::create(2, Color3B::RED, 255, "Click Here", "fonts/arial.ttf", 30, ui::RichElementText::URL_FLAG, "hit_here"));

Comment out the setTouchEnabled line and the RichText will receive input. If anybody knows how to fix this please post a reply. This input problem is preventing us from using RichText in our application (and we could really use it).

I will continue the investigation and post a solution here if I find it.

Does layout->setSwallowTouches(false); help?

Thank you grimfate for your feedback. Yes that does fix the test case I’ve given, however it does not fix the real-world case.

In the real world I need to have the RichText as an element in a modal. The modal has a nine-slice window and a background scrim element that needs to cut off input to the rest of the screen while the modal is active. Plus there are existing input elements behind the modal so there is not an effective way to have a non-layered RichText.

I tried to make my posted sample as simple as possible to show the fundamental error. Since the RichText is layered on top of the layout it should get input first, and that is not happening. I can create a more complex example, but not sure if that would help solve the problem.

Found a fix for this issue, though it requires changes to the RichText ListenerComponent. I posted some information here: Issue with layered RichText input