iCulture forum | iPhone, iPad,  iPod touch, Apple TV en iOS

iCulture forum | iPhone, iPad, iPod touch, Apple TV en iOS (https://forum.iculture.nl/)
-   Ontwikkelen voor iOS (https://forum.iculture.nl/f133/development/f58/ontwikkelen-voor-ios/)
-   -   CoreText drawing geeft ander resultaat dan normale UILabel (https://forum.iculture.nl/f133/development/f58/ontwikkelen-voor-ios/97789-coretext-drawing-geeft-ander-resultaat-normale-uilabel.html)

DJ14 20-08-11 22:33

CoreText drawing geeft ander resultaat dan normale UILabel
 
Hallo allemaal,

Voor een huidig project probeer ik binnen een UILabel bepaalde stukken tekst een andere kleur te geven en te verbinden met een actie. Als eerst heb ik naar UITextView en zijn UIDataDetectorTypes gekeken, maar omdat een UITextView niet de detectie ondersteunt waar ik naar op zoek ben (o.a. hashtags), ben ik bij de UILabels uitgekomen. Wat ik probeer is 2 labels over elkaar plaatsen. Allebei de labels bevatten dezelfde, volledige tekst. Alle tekst in het ene label heeft echter een transparante tekstkleur ([UIColor clearColor]) en in de label zijn bovenop de o.a. hashtags UIButton's geplaatst met actions hieraan verbonden. Het andere label bevat juist de hashtags in transparante kleur, en de rest van de tekst in normale kleur. Zo voorkom ik dat op de plekken van de hashtags 2 lagen tekst overelkaar heen worden geplaatst. Voor het eerste label gebruik ik gewoon een UILabel (geen subclass) met transparante tekst als inhoud, en voor het andere label gebruik ik NSAttributedString in combinatie met het CoreText framework. Helaas is NSAttributedString nog niet optimaal/volledig te gebruiken in iOS, waardoor een workaround vereist is (drawInRect is bijvoorbeeld nog niet ondersteund in iOS, wel in OS X). Dit heb ik allemaal geïmplementeerd; en qua buttons plaatsen en tekst herkennen etc. werkt het. Maar qua layout niet. Wat blijkt: de tekst die met behulp van CoreText gedrawed wordt in het UILabel heeft duidelijk andere eigenschappen. Op onderstaande screenshots is te zien dat de door letters in de door CoreText gedrawde tekst (zwart) dichter op elkaar staan en dat de line-height kleiner is. Toch wordt in beide labels een en dezelfde font (en fontsize) gebruikt. De rode tekst is de tekst waar niets mee is gedaan; de tekst die door een standaard UILabel wordt geproduceerd. Onderstaand staat de code waarmee de tekst op de gesubclasste UILabel wordt gedrawed. Ik heb echt al van alles geprobeerd, zoals textAlignment, kijken naar de rects van de labels (welke exact overheenkomen), rects veranderen, etc. Ik hoop dat iemand de gouden tip heeft die leidt tot oplossing van dit probleem. Thanks,

DJ14


Code:

Code:

- (void)drawTextInRect:(CGRect)aRect
{
   
        if (_attributedText) {
       
                CGContextRef ctx = UIGraphicsGetCurrentContext();
                CGContextSaveGState(ctx);
                // flipping the context to draw core text
                // no need to flip our typographical bounds from now on
                CGContextConcatCTM(ctx, CGAffineTransformScale(CGAffineTransformMakeTranslation(0, self.bounds.size.height), 1.f, -1.f));
                if (self.shadowColor) {
                        CGContextSetShadowWithColor(ctx, self.shadowOffset, 0.0, self.shadowColor.CGColor);
                }
                if (textFrame == NULL) {
                        CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.attributedText);
                        drawingRect = self.bounds;
           
                        CGMutablePathRef path = CGPathCreateMutable();
                        CGPathAddRect(path, NULL, drawingRect);
                        textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL);
                        CGPathRelease(path);
                        CFRelease(framesetter);
                }
                CTFrameDraw(textFrame, ctx);
                CGContextRestoreGState(ctx);
       
    } else {
                [super drawTextInRect:aRect];
        }
   
}


Screenshot:
http://www.pcinside.eu/screenshot_app.png

DJ14 21-08-11 11:57

Het is overigens wel mogelijk om 1 label te gebruiken in plaats van 2, dus dan vervalt de normale UILabel. Met behulp van touchesBegan etc. kunnen stukken van de attributedString klikbaar gemaakt worden. Toch vind ik de uitlijning van de letters van een normaal UILabel mooier dan wanneer de letters door CoreText gedrawed worden. Bovendien wil ik zelf ook gewoon weten waarom dit verschil bestaat. Overigens heb ik meerdere verschillende fonts getest, waaronder HelveticaNeue, Courier, Verdana en ArialMT. Wat opvalt is dat er bij de ene font grotere verschillen zijn, wat betreft de positie van de letters, tussen de tekst gedrawed door een normale UILabel en tussen de tekst gedrawed door CoreText. Heeft iemand hier een idee wat er loos is?

Whacko 22-08-11 17:03

Coretext gebruikt inderdaad andere defaults voor afstanden tussen de letters. Ik weet niet meer precies hoe het aan te passen is, maar het is te doen. Ik heb het een tijd geleden een keer uitgezocht. je moet alleen met wat low-level api's spelen, en wat properties aanpassen. Wat let je trouwens om beiden met Coretext te doen, en dan de touches binnen een bepaald vlak op te vangen, in plaats van een UILabel?

DJ14 22-08-11 18:07

Bedankt voor je reactie. Ondertussen heb ik niet stil gezeten en een oplossing uitgewerkt met behulp van Core Text. Allereerst wordt een NSMutableAttributedString opgemaakt, met [UIColor clearColor] op de plekken van de woorden die hyperlinks moeten worden. Vervolgens heb ik ook met behulp van Core Text de locaties van deze woorden berekend en daarbovenop UIButtons geplaatst (touches opvangen kan ook, maar een button werkt fijner met o.a. de mogelijkheid om de tekst te highlighten). In mijn vorige post had ik al aangegeven dat het ook op deze manier kon, maar dat ik de uitlijning van de letters in een normale UILabel mooier vind.

DJ14 24-09-11 13:36

We zijn nu een maand verder, en intussen heb ik verschillende manieren geprobeerd om datgene te bereiken wat ik wil bereiken. Zo heb ik bijvoorbeeld ook met CoreText gewerkt en over bepaalde runs buttons te plaatsen, maar op een of andere manier werden deze buttons telkens net niet op de juiste plek geplaatst (terwijl ik gewoon de positie van de runs opvraag en precies daaroverheen buttons zet). Nu denk ik dat de beste manier is om core text te gebruiken, en vervolgens door het scannen van de tekst (ipv core text runs te gebruiken) op de juiste 'woorden' buttons te plaatsen. Daarvoor moet ik alleen een NSAttributedString zo formatteren, dat deze exact dezelfde text layout heeft als een UILabel (zelfde letterafstand etc.). Op internet ben ik echter nog niks tegengekomen waarmee ik dit kan bereiken. Iemand enig idee?


Alle tijden zijn GMT +2. Het is nu 13:00.