cocos2d-objc
cocos2d-objc copied to clipboard
[iOS] Attributed String does not work in CCLabelTTF
[SpriteBuilder 1.3.6, Cocos2D-Swift version 3.3.0-develop]
I have not manage to get CCLabelTTF to work with attributedString. If you create a starting project with SpriteBuilder. Add Code Connection from the label and add label property in MainScene. Run this code:
NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:@"Hello"];
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,2)];
self.label.attributedString = attributedString;
What is expected is "He" to become red. What happens is a crash.
I can post more details but I believe everyone will be able to reproduce this.
Please can you retest in SB 1.4 Beta http://forum.spritebuilder.com/t/spritebuilder-1-4-beta-release/2573
Thanks
This is still broken in Cocos2d 3.4.3. Properties of an AttributedString are not being honored (such as font and paragraph styles) and setting a text foreground color causes a crash. It seems like CCLabelTTF is just seriously broken since v3.3. It was fine in v3.2.1 and maybe has something to do with very deep code in the renderer or drawing routines.
If you create a CCLabelTTF with an attributed string, there's no crash until you actually add it to the stage (scene). If you create one with an attributed string that has paragraph and font attributes but no NSForegroundColor attributes and -- for instance -- color the text using label.fontColor, then you will actually not crash but you will get a so-colored label that's missing the paragraph and font attrubutes set on the attributed string.
It is not sufficient to rely on using the CCLabel fontName, fontSize, fontColor becuase we want to be able to use an attributed string with varying attributes across different ranges of the string. We want to be able to have different colors, font sizes, paragraph setting, etc. like we used to have in Cocos2d 3.2.1. Please fix this -- it has caused me lots of grief in trying to get an app ready for the App Store on a high-profile project. Thanks.
@Birkemose Would you be able to look at this ? Thanks
Sure
On 26 Jan 2015, at 10:17, cocojoe [email protected] wrote:
@Birkemose https://github.com/Birkemose Would you be able to look at this ? Thanks
— Reply to this email directly or view it on GitHub https://github.com/cocos2d/cocos2d-swift/issues/1153#issuecomment-71432198.
I'm kind of depending on this feature too... well, I will test any fixes :-)
I looked at this in 3.3, but was unable to find out why CCLabelTTF crashes. I was under the impression it had been fixed in 3.4?
On 07 Feb 2015, at 19:30, jonnyijapan [email protected] wrote:
I'm kind of depending on this feature too... well, I will test any fixes :-)
— Reply to this email directly or view it on GitHub https://github.com/cocos2d/cocos2d-swift/issues/1153#issuecomment-73376422.
I have been looking into this again, and my bad for thinking it was fixed.
Just to recap. When launching cocos2d-tests-ios on ex. iPad2 (8.1), an exception is thrown in line 75 of CCLabelTTF.m. I do not know the reason why, or if it has anything to do with this problem.
After that, almost any attempt to add a string with attributes, causes an unrecoverable crash in line 402 of CCLabelTTF. Very basic attributed strings will work, but adding pretty much any attribute, will cause the crash.
Googling around a bit, leads me to believe it has something to do with the font setup, but I do not have sufficient experience with Core Text functionality, to know what to look for.
On 08 Feb 2015, at 16:06, Lars Birkemose [email protected] wrote:
I looked at this in 3.3, but was unable to find out why CCLabelTTF crashes. I was under the impression it had been fixed in 3.4?
On 07 Feb 2015, at 19:30, jonnyijapan <[email protected] mailto:[email protected]> wrote:
I'm kind of depending on this feature too... well, I will test any fixes :-)
— Reply to this email directly or view it on GitHub https://github.com/cocos2d/cocos2d-swift/issues/1153#issuecomment-73376422.
Thanks so much! Does someone else on the team have more insight perhaps? It definitely used to work fine, but whatever changes occurred in 3.3 or thereabouts have caused problems with this. The fact that it doesn't crash unless you actually add your label to the stage makes me think the issue is deep in the renderer, but is that a silly theory? I mean, you can create as many complex labels as you want but it's only if you want to see them that you crash. It worked fine in 3.2.1 at least. Would love for this functionality to return in the future! 😻
We should at least have a test case that can show that it did work in 3.2 but not since 3.x... So it will be easier for anyone who wants to take on the task.
I have a test case which works in older version. This should just be added to the iOS tests.
On 09 Feb 2015, at 18:12, jonnyijapan [email protected] wrote:
We should at least have a test case that can show that it did work in 3.2 but not since 3.x... So it will be easier for anyone who wants to take on the task.
— Reply to this email directly or view it on GitHub https://github.com/cocos2d/cocos2d-swift/issues/1153#issuecomment-73548009.
The problem with attributes not being applied in iOS (all I've looked at so far) seems to be in NSMutableAttributedStringFixPlatformSpecificAttributes in Support/NSAttributedString+CCAdditions.m
For some reason, if not running on Android, it reapplies a font attribute to the string - but only the first font attribute it comes across and to the whole string (fullRange) - removing any changes to font size, etc later on in the string. Commenting out lines 264 to 269 stops this, but the font attribute is then again set on the 'fullRange' on line 333 - so commenting that line is also required to make font size attributes work on iOS.
Hopefully that helps someone who fully understands what this method is trying to achieve to resolve the issues...
Just want to change the color? CCLabelBMFont might do what you need.
I did some fixes to CCLabelBMFont recently. That class always promised that you could apply effects to individual font char sprites but it was impossible because of the caching/re-use and new-line mangling that went on mean the index of the child didn't correspond to the string. That now works and I added a convenience method that allows you to get a list of the sprites for a range.
- https://github.com/cocos2d/cocos2d-swift/pull/1210
- https://github.com/cocos2d/cocos2d-swift/pull/1240
Note that the second pull request hasn't been accepted yet, and fixes some bugs relating to FooBar.bmfont style fonts used by SpriteBuilder.
One cause of this is a faulty comparison of NSAttributedString equality in CCLabelTTF
https://github.com/cocos2d/cocos2d-objc/blob/v3.4/cocos2d/CCLabelTTF.m#L159
if ( _attributedString.hash != attributedString.hash)
should be
if ( ![_attributedString isEqualToAttributedString: attributedString])
Patching this locally resolves the issue for me
Any update on this issue? The solution from @SRandazzo did not work for me. I am also running v3.4.3 and observe the same crash when setting NSForegroundColorAttributeName on CCLabelTTF attributedStrings. Thanks!
I am in the process of going through issues for the final release of 3.4.9, so hopefully this week
Excellent, looking forward to the upcoming release. Please let me know if you need any help testing anything out!
hash is guaranteed to be identical for identical strings, so comparing hash and using isEqualToString, should be the same. No idea why they chose to use hash
@SRandazzo @Birkemose about crash: there is bug in NSMutableAttributedStringFixPlatformSpecificAttributes method in NSAttributedString+CCAdditions.m, as we see in line [string addAttribute:(id)kCTForegroundColorFromContextAttributeName value:(__bridge id)color range:fullRange];
for kCTForegroundColorFromContextAttributeName used 'color' (CGColorRef) as value, but as described in comment for this attribute (kCTForegroundColorFromContextAttributeName), value must be CFBooleanRef. It's why cocos2d code is crashing when user wants to use NSForegroundColorAttributeName attribute in attributed string. Value should be something like [NSNumber numberWithBool:YES].
@mstorch there is workaround (if you still interested :-))
for example if you have attributed string:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:str];
instead of setting attribute like this:
[text addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:somerange];
you should use CoreText attribute name like this:
CGColorRef color = CGColorRetain([UIColor redColor].CGColor);
[text addAttribute:(id)kCTForegroundColorAttributeName value:(__bridge id)color range:somerange];
CGColorRelease(color);