UILabel justify left and right - iphone

i have UILabel (cocoa touch framework) and i want to right and left justify its text.
as a consequence it will stretch the text inside.
Example:
like if i had this text "While the saved costs of physical manufacturing and shipping" it would appear like the following:
"While the saved"
"c o s t s o f"
"p h y s i c a l"
"manufacturing"
"a n d shipping"
as you can see left and right justification...
how can i achieve that ???
many thanks
i'm sorry i had to put the double qoutations to post the question.

You should use my OHAttributedLabel class.
It has everything needed to display an NSAttributedString, including justifying left, center, right… and justified, and is really simple to use.
You can find it here on github. See the sample code provided that also shows how to change text justification.
// suppose that label is an IBOutlet to an OHAttributedLabel (subclass oh UILabel)
label.textAlignment = UITextAlignmentJustify; // and that's all, OHAttributedLabel does everything needed for you!
(Note: UITextAlignmentJustify is a constant defined in OHAttributedLabel headers that matches corresponding CoreText constant for justify alignment. This constant does not exists in Apple's SDK)
[EDIT] iOS6 SDK
Since iOS6 SDK, the UITextAlignmentJustify does not work anymore and generate a crash at runtime. Now you should set the text alignment of your NSAttributedString itself instead of using the textAlignment property of the label.

Using UIWebView can be slow, so if that's an issue CoreText is the way to go.
Here's some code that uses core text to display an attributed string on a view. It indents a bit like UILabel. I've left some other paragraph formatting options in to illustrate how you can set other paragraph properties and also set the attributed string to bold. Remember you'll need to add the CoreText framework otherwise you'll get build errors.
This code doesn't full justify the last line. Not sure you can get this for free in CoreText.
the .h file
//
// SmartLabel.h
//
#import <UIKit/UIKit.h>
#import <CoreText/CoreText.h> // needed for CTFontRef, CTFontCreateWithName
#interface SmartLabel : UIView
{
NSMutableAttributedString* _pgSmartString;
}
#property (nonatomic, retain) NSMutableAttributedString* smartString;
- (void) setText: (NSString*) string;
- (void) formatString;
#end
And the .m file
//
// SmartLabel.m
//
#import "SmartLabel.h"
#implementation SmartLabel
#synthesize smartString = _pgSmartString;
- (void)dealloc
{
[_pgSmartString release];
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame;
{
if ((self = [super initWithFrame:frame]))
{
[self setBackgroundColor: [UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef graphicsContext = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(graphicsContext, CGAffineTransformIdentity);
// turns things right way up
CGContextTranslateCTM(graphicsContext, 0, self.bounds.size.height);
CGContextScaleCTM(graphicsContext, 1.0, -1.0);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)[self smartString]);
CGRect bounds = [self bounds];
bounds.origin.x = bounds.origin.x + 8;
bounds.size.width = bounds.size.width - 16;
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, bounds);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [[self smartString] length]), path, NULL);
CFRelease(path);
CTFrameDraw(frame, graphicsContext);
CFRelease(frame);
CFRelease(framesetter);
}
- (void) setText: (NSString*) string;
{
NSMutableAttributedString* attributedString = [[NSMutableAttributedString alloc] initWithString:string];
[self setSmartString:attributedString];
[attributedString release];
[self formatString];
}
- (void) formatString;
{
CTTextAlignment alignment = kCTJustifiedTextAlignment; // could put different alignments here
CGFloat paragraphSpacing = 11.0;
CGFloat paragraphSpacingBefore = 0.0;
CGFloat firstLineHeadIndent = 0.0;
CGFloat headIndent = 0.0;
CTParagraphStyleSetting altSettings[] =
{
{ kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment},
{ kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(CGFloat), &firstLineHeadIndent},
{ kCTParagraphStyleSpecifierHeadIndent, sizeof(CGFloat), &headIndent},
{ kCTParagraphStyleSpecifierParagraphSpacing, sizeof(CGFloat), &paragraphSpacing},
{ kCTParagraphStyleSpecifierParagraphSpacingBefore, sizeof(CGFloat), &paragraphSpacingBefore},
};
CTParagraphStyleRef style;
style = CTParagraphStyleCreate( altSettings, sizeof(altSettings) / sizeof(CTParagraphStyleSetting) );
if ( style == NULL )
{
NSLog(#"*** WARNING *** Unable To Create CTParagraphStyle in apply paragraph formatting" );
return;
}
[[self smartString] addAttributes:[NSDictionary dictionaryWithObjectsAndKeys:(NSObject*)style,(NSString*) kCTParagraphStyleAttributeName, nil] range:NSMakeRange(0,[[self smartString] length])];
CFRelease(style);
UIFont* boldFont = [UIFont boldSystemFontOfSize:12.0];
CTFontRef boldCoreTextFontReference = CTFontCreateWithName ((CFStringRef)[boldFont fontName],[boldFont pointSize], NULL);
[[self smartString] addAttributes:[NSDictionary dictionaryWithObjectsAndKeys:(NSObject*)boldCoreTextFontReference,(NSString*) kCTFontAttributeName, nil] range:NSMakeRange(0,[[self smartString] length])];
}
#end
And to put to use, something like this:
SmartLabel* smartLabel = [[SmartLabel alloc] initWithFrame:CGRectMake(20, 120, 90, 140.0)];
[[self window] addSubview:smartLabel];
[smartLabel setText:#"While the saved costs of physical manufacturing and shipping"];
[smartLabel release];

Its very easy after the release of IOS 6.
Use this
//build a style for justification
NSMutableParagraphStyle *stringStyle=[[NSMutableParagraphStyle alloc]init];
[stringStyle setAlignment:NSTextAlignmentJustified];
//build a string with the particular paragraph style
NSMutableAttributedString* yourString=[[NSMutableAttributedString alloc]init];
[yourString addAttribute:NSParagraphStyleAttributeName value:stringStyle range:NSMakeRange(0, [yourString length])];
//and here you go
UILabel *yourLabel;
yourlabel.attributedText=yourString;

From iOS 6 you can use NSMutableAttributedString for this,
NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithData:[#"Your String value" dataUsingEncoding:NSUTF8StringEncoding] options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil];
NSRange rangeOfTitle = NSMakeRange(0,[attrStr length]);
[attrStr addAttribute: NSFontAttributeName value:[UIFont fontWithName:#"Calibri" size:19.0]range:rangeOfTitle];
myLabel.attributedText = attrStr;
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:10];
style.lineBreakMode = NSLineBreakByWordWrapping;
style.alignment = NSTextAlignmentJustified;
[attrStr addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, myLabel.text.length)];
myLabel.attributedText = attrStr;

The perfect solution is to used NSMutableParagraphStyle
NSMutableParagraphStyle *paragraphStyles = [[NSMutableParagraphStyle alloc] init];
paragraphStyles.alignment = NSTextAlignmentJustified; //justified text
paragraphStyles.firstLineHeadIndent = 1.0;
NSDictionary *attributes = #{NSParagraphStyleAttributeName: paragraphStyles};
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: YourString attributes: attributes];
YourLabel.attributedText = attributedString;

This is so called "full justification", but isn't supported by the UILabel system (which only has "alignments" - left, right and centre). If you want this, you'll have to code it up yourself, building a control with CoreText or similar.

Agree that this can only be done with a good bit of custom coding; which I would think will be some pretty heavy stuff. Before you get into that; and this is depending on your requirement; do consider having a UIWebView where I imagine you would be able to manage text styles and alignments with a bit more freedom using some HTML and CSS coding.

The following works as a quick fix, but note that for anything more than black plain text you'll need some styling or css.
(From: Justified Alignment in UITextView - iPhone)
I have come to a solution that works. First of all, you will need to change your UITextView and use a UIWebView instead.
Details.h
#interface Details : UIViewController {
IBOutlet UIWebView *descripcion;
}
#property (nonatomic, retain) UITextView *descripcion;
Then, load your UIWebView as follows:
Details.m
[descripcion loadHTMLString:[NSString stringWithFormat:#"<div align='justify'>%#<div>",YOUR_TEXT] baseURL:nil];

Related

Custom UIPickerView with three Components each showing label on Selection Indicator

In my app I am trying to make an custom UIPickerView which contains three components(days, hours and minutes). I have already made the custom picker with three components. And Now I am stuck at how I can add the labels to the selection indicator which shows which component is for days, hours or minutes.
I have already gone through each and every link or question posted on this site but none them helped me.
I am trying to implement something like this image
Can any one suggest me how can I achieve this?
Thats how I achieve this....I have made my Custom PickerView with the help of some code I found...
In .h file:
// LabeledPickerView.h
// LabeledPickerView
#import <UIKit/UIKit.h>
#interface LabeledPickerView : UIPickerView
{
NSMutableDictionary *labels;
}
/** Adds the label for the given component. */
-(void)addLabel:(NSString *)labeltext forComponent:(NSUInteger)component forLongestString:(NSString *)longestString;
#end
and In the .m file...
// LabeledPickerView.m
// LabeledPickerView
#import "LabeledPickerView.h"
#implementation LabeledPickerView
/** loading programmatically */
- (id)initWithFrame:(CGRect)aRect {
if (self = [super initWithFrame:aRect]) {
labels = [[NSMutableDictionary alloc] initWithCapacity:3];
}
return self;
}
/** loading from nib */
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
labels = [[NSMutableDictionary alloc] initWithCapacity:3];
}
return self;
}
- (void) dealloc
{
[labels release];
[super dealloc];
}
#pragma mark Labels
// Add labelText to our array but also add what will be the longest label we will use in updateLabel
// If you do not plan to update label then the longestString should be the same as the labelText
// This way we can initially size our label to the longest width and we get the same effect Apple uses
-(void)addLabel:(NSString *)labeltext forComponent:(NSUInteger)component forLongestString:(NSString *)longestString {
[labels setObject:labeltext forKey:[NSNumber numberWithInt:component]];
NSString *keyName = [NSString stringWithFormat:#"%#_%#", #"longestString", [NSNumber numberWithInt:component]];
if(!longestString) {
longestString = labeltext;
}
[labels setObject:longestString forKey:keyName];
}
//
- (void) updateLabel:(NSString *)labeltext forComponent:(NSUInteger)component {
UILabel *theLabel = (UILabel*)[self viewWithTag:component + 1];
// Update label if it doesn’t match current label
if (![theLabel.text isEqualToString:labeltext]) {
NSString *keyName = [NSString stringWithFormat:#"%#_%#", #"longestString", [NSNumber numberWithInt:component]];
NSString *longestString = [labels objectForKey:keyName];
// Update label array with our new string value
[self addLabel:labeltext forComponent:component forLongestString:longestString];
// change label during fade out/in
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.75];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
theLabel.alpha = 0.00;
theLabel.text = labeltext;
theLabel.alpha = 1.00;
[UIView commitAnimations];
}
}
/**
Adds the labels to the view, below the selection indicator glass-thingy.
The labels are aligned to the right side of the wheel.
The delegate is responsible for providing enough width for both the value and the label.
*/
- (void)didMoveToWindow {
// exit if view is removed from the window or there are no labels.
if (!self.window || [labels count] == 0)
return;
UIFont *labelfont = [UIFont boldSystemFontOfSize:15];
// find the width of all the wheels combined
CGFloat widthofwheels = 0;
for (int i=0; i<self.numberOfComponents; i++) {
widthofwheels += [self rowSizeForComponent:i].width;
}
// find the left side of the first wheel.
// seems like a misnomer, but that will soon be corrected.
CGFloat rightsideofwheel = (self.frame.size.width - widthofwheels) / 2;
// cycle through all wheels
for (int component=0; component<self.numberOfComponents; component++) {
// find the right side of the wheel
rightsideofwheel += [self rowSizeForComponent:component].width;
// get the text for the label.
// move on to the next if there is no label for this wheel.
NSString *text = [labels objectForKey:[NSNumber numberWithInt:component]];
if (text) {
// set up the frame for the label using our longestString length
NSString *keyName = [NSString stringWithFormat:#"%#_%#", [NSString stringWithString:#"longestString"], [NSNumber numberWithInt:component]];
NSString *longestString = [labels objectForKey:keyName];
CGRect frame;
frame.size = [longestString sizeWithFont:labelfont];
// center it vertically
frame.origin.y = (self.frame.size.height / 2) - (frame.size.height / 2) - 0.5;
// align it to the right side of the wheel, with a margin.
// use a smaller margin for the rightmost wheel.
frame.origin.x = rightsideofwheel - frame.size.width -
(component == self.numberOfComponents - 1 ? 5 : 7);
// set up the label. If label already exists, just get a reference to it
BOOL addlabelView = NO;
UILabel *label = (UILabel*)[self viewWithTag:component + 1];
if(!label) {
label = [[[UILabel alloc] initWithFrame:frame] autorelease];
addlabelView = YES;
}
label.text = text;
label.font = labelfont;
label.backgroundColor = [UIColor clearColor];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake(0,1);
// Tag cannot be 0 so just increment component number to esnure we get a positive
// NB update/remove Label methods are aware of this incrementation!
label.tag = component + 1;
if(addlabelView) {
/*
and now for the tricky bit: adding the label to the view.
kind of a hack to be honest, might stop working if Apple decides to
change the inner workings of the UIPickerView.
*/
if (self.showsSelectionIndicator) {
// if this is the last wheel, add label as the third view from the top
if (component==self.numberOfComponents-1)
[self insertSubview:label atIndex:[self.subviews count]-3];
// otherwise add label as the 5th, 10th, 15th etc view from the top
else
[self insertSubview:label aboveSubview:[self.subviews objectAtIndex:5*(component+1)]];
} else
// there is no selection indicator, so just add it to the top
[self addSubview:label];
}
if ([self.delegate respondsToSelector:#selector(pickerView:didSelectRow:inComponent:)])
[self.delegate pickerView:self didSelectRow:[self selectedRowInComponent:component] inComponent:component];
}
}
}
And call this addLabel: method with the label text and component tag and thats it..!!
Download the Source code Of custom UIPickerView Control .
Custom UiPickerView.
Hope it Helps to You :)

How to have a Score Integer updated and displayed in Cocos2d?

I am obviously making a game that has a score. How do I call an update method and have the integer actually displayed in the Top-Right corner?
Here, this might work
In the .h file:
#interface HelloWorld : CCLayer {
int score;
CCLabelTTF *scoreLabel;
}
- (void)addPoint;
In the .m file:
In the init method:
//Set the score to zero.
score = 0;
//Create and add the score label as a child.
scoreLabel = [CCLabelTTF labelWithString:#"8" fontName:#"Marker Felt" fontSize:24];
scoreLabel.position = ccp(240, 160); //Middle of the screen...
[self addChild:scoreLabel z:1];
Somewhere else:
- (void)addPoint
{
score = score + 1; //I think: score++; will also work.
[scoreLabel setString:[NSString stringWithFormat:#"%#", score]];
}
Now just call: [self addPoint]; whenever the user kills an enemy.
That should work, tell me if it didn't because I have not tested it.
in header file:
#interface GameLayer : CCLayer
{
CCLabelTTF *_scoreLabel;
}
-(void) updateScore:(int) newScore;
in implementation file:
-(id) init
{
if( (self=[super init])) {
// ..
// add score label
_scoreLabel = [CCLabelTTF labelWithString:#"0" dimensions:CGSizeMake(200,30) alignment:UITextAlignmentRight fontName:#"Marker Felt" fontSize:30];
[self addChild:_scoreLabel];
_scoreLabel.position = ccp( screenSize.width-100, screenSize.height-20);
}
return self;
}
-(void) updateScore:(int) newScore {
[_scoreLabel setString: [NSString stringWithFormat:#"%d", newScore]];
}
EDIT: if you don't want to use an ivar, you can use tags:
[self addChild:scoreLabel z:0 tag:kScoreLabel];
// ...
CCLabelTTF *scoreLabel = (CCLabelTTF*)[self getChildByTag:kScoreLabel];
EDIT 2: For performance reasons you should switch to CCLabelAtlas or CCBitmapFontAtlas if you update the score very frequently.
Also read the cocos2d programming guide about labels.
Using UILabel
UILabel.text = [NSString stringWithFormat:#"%lu",score];
Move the UILabel in the top of the view using interface builder
you could also create it programmatically
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,500,30)];
[[self view] addSubview:label];
[label release]; // dont leak :)

iPhone SDK 3.2 and UIAppFonts

I've added my custom font to UIAppFonts and it's loaded just fine: (shows up in [UIFont familyNames] ). When I manually set the font in viewDidLoad { [myLabel setFont: [UIFont fontWithName:#"CustomFont" size: 65.0]]; } everything works and the font is rendered.
However doing the same thing in IB doesn't (some other default font is used instead). Having to create IBOutlets for each label and fixing up the fonts manually in viewDidLoad is pretty painful.
Anyone else had problems getting the custom font support to work with 3.2 SDK and IB?
Opened a bug report with Apple and turns out it really is a bug. The workaround I ended up using is this:
// LabelQuake.h
#interface LabelQuake : UILabel
#end
// LabelQuake.m
#implementation LabelQuake
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder: decoder]) {
[self setFont: [UIFont fontWithName: #"Quake" size: self.font.pointSize]];
}
return self;
}
#end
Wrote a bit longer post at our blog.
had simillar kind of problem.and fixed it in this way...
add my custom font to my Resource group. then load all the fonts by the code given bellow:
- (NSUInteger) loadFonts{
NSUInteger newFontCount = 0;
NSBundle *frameworkBundle = [NSBundle bundleWithIdentifier:#"com.apple.GraphicsServices"];
const char *frameworkPath = [[frameworkBundle executablePath] UTF8String];
if (frameworkPath) {
void *graphicsServices = dlopen(frameworkPath, RTLD_NOLOAD | RTLD_LAZY);
if (graphicsServices) {
BOOL (*GSFontAddFromFile)(const char *) = dlsym(graphicsServices, "GSFontAddFromFile");
if (GSFontAddFromFile)
for (NSString *fontFile in [[NSBundle mainBundle] pathsForResourcesOfType:#"ttf" inDirectory:nil])
newFontCount += GSFontAddFromFile([fontFile UTF8String]);
}
}
return newFontCount;}
- (id)initWithCoder:(NSCoder *)decoder {
//load the fonts
[self loadFonts];
if (self = [super initWithCoder: decoder]) {
[self setFont: [UIFont fontWithName: #"Quake" size: self.font.pointSize]];
}
return self;
}
Hope it will work.
If you don't want to have to subclass, this solution worked quick and dirty for me. Of course it assumes that all labels have the same font, and in my case that was the case.
for (UIView *v in view.subviews) {
if ([v isKindOfClass:[UILabel class]]) {
UILabel *label = (UILabel*)v;
[label setFont:[UIFont fontWithName:#"Quake" size:label.font.pointSize]];
}
}
I put this in a helper class and just called it, passing in my current view.

Can we set the dropdown list for the textfield to select an option in iphone sdk?

I need a textfield which has an dropdown list to select an option from that.Is there any possible chances to do that in Iphone sdk?
Guys I need a quick help from ur side.
Anyone's help will be much appreciated.
Thank you,
Monish.
You use a UIPickerView instead of a dropdown list.
Edit: i missed the text field part. You are emulating a combo box.
You can use a picker + text field, and fill the text field from the pickerView:didSelectRow:inComponent delegat method
Edit2: There are some S/O questions about this already - related to UIPickerView bugs
-(void)textFieldDidBeginEditing:(UITextField *)textField{
[self gotodropdown];
}
-(void)dropdown
{
if(dropDownView==nil && ([copyListOfItems count] > 0))
{
dropDownView = [[DropDownView alloc] initWithArrayData:copyListOfItems heightTableView:200 paddingTop:0 paddingLeft:0 paddingRight:0 refView:textField animation:BOTH openAnimationDuration:2 closeAnimationDuration:0.5 ];
dropDownView.delegate = self;
[dropDownView openAnimation];
[self addSubview:dropDownView.view];
}
}
//dropdown.m
- (id)initWithArrayData:(NSMutableArray *)data heightTableView:(CGFloat)tHeightTableView paddingTop:(CGFloat)tPaddingTop paddingLeft:(CGFloat)tPaddingLeft paddingRight:(CGFloat)tPaddingRight refView:(UIView*)rView animation:(AnimationType)tAnimation openAnimationDuration:(CGFloat)openDuration closeAnimationDuration:(CGFloat)closeDuration {
if ((self = [super init])) {
//array=[[NSMutableArray alloc]init];
//[array addObjectsFromArray:data];
self.array = [data retain];
NSLog(#"ARRAYIS:%#",data);
self.refView = rView;
self.paddingTop = tPaddingTop;
self.paddingLeft = tPaddingLeft;
self.paddingRight = tPaddingRight;
self.heightTableView = tHeightTableView;
self.open = openDuration;
self.close = closeDuration;
CGRect refFrame = refView.frame;
self.view.frame = CGRectMake(refFrame.origin.x-paddingLeft,refFrame.origin.y+refFrame.size.height+paddingTop,refFrame.size.width+paddingRight, heightTableView);
self.view.layer.shadowColor = [[UIColor blackColor] CGColor];
self.view.layer.shadowOffset = CGSizeMake(5.0f, 5.0f);
self.view.layer.shadowOpacity =1.0f;
self.view.layer.shadowRadius = 5.0f;
animationType = tAnimation;
}
return self;
}
use tableview delegate for further details

TTStyledTextLabel offset between link and regular text when changing from default font

I'm using Three20 TTStyledTextLabel and when I change the default font (Helvetica) to something else it creates some kind of height difference between links and regular text
The following code demonstrate my problem:
#import <Three20/Three20.h>
#interface TestController : UIViewController {
}
#end
#implementation TestController
-(id)init{
self = [super init];
TTStyledTextLabel* label = [[[TTStyledTextLabel alloc] initWithFrame:CGRectMake(0, 0, 320, 230)] autorelease];
label.text = [TTStyledText textFromXHTML:#"link text" lineBreaks:YES URLs:YES];
[label setFont:[UIFont systemFontOfSize:16]];
[[self view] addSubview:label];
TTStyledTextLabel* label2 = [[[TTStyledTextLabel alloc] initWithFrame:CGRectMake(0, 230, 320, 230)] autorelease];
label2.text = [TTStyledText textFromXHTML:#"link2 text2" lineBreaks:YES URLs:YES];
[label2 setFont:[UIFont fontWithName:#"HelveticaNeue" size:16]];
[[self view] addSubview:label2];
return self;
}
#end
In the screen shot you can see that the first link is aligned and the second one isn't
How do I fix it? I think there is a bug in the TTStyledTextLabel code...
i just commented - (void)offsetFrame:(TTStyledFrame*)frame by:(CGFloat)y (TTStyledLayout.m:87) out and it did the trick. of course it may break other stuff.
edit:
i also commented out the following bits of code
if (!font) {
// if ([elt isKindOfClass:[TTStyledLinkNode class]]
// || [elt isKindOfClass:[TTStyledBoldNode class]]) {
// font = self.boldFont;
// } else if ([elt isKindOfClass:[TTStyledItalicNode class]]) {
// font = self.italicFont;
// } else {
font = self.font;
// }
}
to get rid of the bold font.
In the latest version of three20 as of this writing, it seems to me that the problem lives at TTStyledLayout:345.
Specifically, changing:
[self offsetFrame:frame by:(_lineHeight - (frame.height - font.descender))];
to
[self offsetFrame:frame by:(_lineHeight - (frame.height /* - font.descender */ ))];
... seems to solve the problem.
After staring at the TT code for awhile, I believe your problem only crops up when there are URLs on a line because URL boldness inflates some "line height" ivar. If you don't want to fork three20, you could probably just alter your stylesheet to ensure the line heights of URLs are no different than the line height of the rest of your text. I'm just speculating, though.
I plan on filing a bug report about this, too.
If you look at the source code, the font is set using a style: self.font = TTSTYLEVAR(font). I would do two things here
Create a Category that overrides the initWithFrame method. Leave everything the same except rename self.font = TTSTYLEVAR(font) to something else like tableXFont so that changing the font style will not affect your whole app.
Make and register your own stylesheet so that the tableXFont is defined.
This should set you on the right path to the proper way to do three20 font and styling customization
This is better, so it won't change the style of TTStyledBoldNodeclass
Original Code:
if (!font) {
if ([elt isKindOfClass:[TTStyledLinkNodeclass]]
|| [elt isKindOfClass:[TTStyledBoldNodeclass]]) {
font = self.boldFont;
} elseif ([elt isKindOfClass:[TTStyledItalicNodeclass]]) {
font = self.italicFont;
} else {
font = self.font;
}
}
Fixed Code:
if (!font) {
if ([elt isKindOfClass:[TTStyledBoldNodeclass]]) {
font = self.boldFont;
} elseif ([elt isKindOfClass:[TTStyledItalicNodeclass]]) {
font = self.italicFont;
} else {
font = self.font;
}
}