UILabel text layout when wrapping is "wrong" in iOS 7 - uilabel

The screen shot below is in iOS 7. label1 (yellow, top) is drawn with the text origin below the top left of the its frame and clipped at the bottom. In iOS 5/6 the text origin is the top left of the label frame. label2 and label3 render and layout as expected.
Here is the code to generate this view:
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:UIScreen.mainScreen.applicationFrame];
view.backgroundColor = UIColor.blueColor;
self.view = view;
UILabel *label1 = [UILabel new];
label1.backgroundColor = UIColor.yellowColor;
label1.font = [UIFont systemFontOfSize:16.0f];
label1.numberOfLines = 0;
label1.lineBreakMode = NSLineBreakByWordWrapping;
label1.frame = CGRectMake(50, 100, 200, 18);
label1.text = #"This text is too long to fit on one line.";
[self.view addSubview:label1];
UILabel *label2 = [UILabel new];
label2.backgroundColor = UIColor.greenColor;
label2.font = [UIFont systemFontOfSize:16.0f];
label2.numberOfLines = 0;
label2.lineBreakMode = NSLineBreakByWordWrapping;
label2.frame = CGRectMake(50, 150, 200, 36);
label2.text = #"This text is too long to fit on one line.";
[self.view addSubview:label2];
UILabel *label3 = [UILabel new];
label3.backgroundColor = UIColor.orangeColor;
label3.font = [UIFont systemFontOfSize:16.0f];
label3.numberOfLines = 0;
label3.lineBreakMode = NSLineBreakByWordWrapping;
label3.frame = CGRectMake(50, 200, 200, 18);
label3.text = #"This text is short.";
[self.view addSubview:label3];
}
QUESTION: Why is this different in iOS 7 and what label properties do I need to change to have the text in label1 render starting from the top left of its frame as expected.

I figured it out. Rather than delete my question, I'll answer it here so if anyone else runs into this they know what to do.
The label frames are hardcoded to specific sizes. In the case of label1, the height is 18. This bound is not tall enough to render a line of text with a system font at 16 points. iOS 5/6 apparently top align the text rect whereas in iOS 7 this causes unpredictable behavior. This fix is to ensure the label bounds are tall enough to display at least one line of text.
The sample code in the question was for the purposes of reproducing this problem. My actual app code calculates label heights based on desired number of lines with various other views positioned around the label so the frame is changed dynamically at run time. I fixed the problem in my app by ensuring the minimum label height can fit a single line of text.

Related

SKLabelNode sometimes disappear in iOS 9.2

I have a node with a picture of a box added right on top of another node with image of an airship:
SKSpriteNode *box = [SKSpriteNode spriteNodeWithImageNamed:#"Box"];
box.position = airshipNode.position;
box.physicsBody = [SKPhysicBody bodyWithRectangleOfSize:box.size];
box.physicsBody.categoryBitMask = 1;
box.physicsBody.collisionBitMask = 0;
box.zPosition = airship.zPosition - 1;
[box setScale:0.7];
Now I added a label on top of the box:
SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:#"Arial"];
CGPoint *position = box.centerRect.origin;
position.y -= 55;
label.position = box.centerRect.origin;
label.text = #"a";
label.fontSize = 70;
label.fontColor = [SKColor blackColor];
Then I added the label onto the box and box onto the main scene:
[box addChild:label];
// self is the main scene.
[self addChild:box];
Then I call these code every 1 second. But the label only appears on some of them and the others are just the box, no label. I also added a fade out action for when the box was tapped. But when the fade out animation is going, the label on the box without the text starts to appear. Any ideas on why the label is not appearing on initializations? Thanks.
After a bits of researching, I found iOS 9's Sprite Kit handle default z position a bit different than iOS 8. So by adding this line will make all of the labels appear:
label.zPosition = box.zPosition + 1

Get the number of lines in UILabel iOS8

I'm seeing lots of deprecated answers for this question:
How do I calculate the number of lines in use in a UILabel based of its set text?
I know that I need to set the UILabel to have bounds that resize with word wrapping. In this way, I could detect the height of my UILabel and adjust an NSLayoutConstraint for the height of my UITableViewCell. Basically my problem plain and simple is:
How can I determine my UILabel's number of lines in use(based of descriptionLabel.text) or height in order to resize My UITableView's UITableViewCells which contain my UILabel.
Currently I have used this code:
descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, 30, 270, 65)];
descriptionLabel.textColor = [UIColor blackColor];
descriptionLabel.numberOfLines = 0;
descriptionLabel.adjustsFontSizeToFitWidth = YES;
Try using the following code
NSAttributedString *attrStr = ... // your attributed string
CGFloat width = 300; // whatever your desired width is
CGRect rect = [attrStr boundingRectWithSize:CGSizeMake(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
//rect is the height of UILABEL which u can used as height of label or table view row or etc
I solved my problem very simply with this code:
CGSize maxSize = CGSizeMake(290.0f, CGFLOAT_MAX);
CGSize requiredSize = [descriptionLabel sizeThatFits:maxSize];
[descriptionLabel setFrame:CGRectMake(15, 50, requiredSize.width, requiredSize.height)];
NSLog(#"THE HEIGHT OF THIS DESCRIPTIONLABEL IS: %f",cell.frame.size.height);

Drawing line through UITableView cells

Is it possible to draw a line with different width through some cells in UITableView?
Something like this:
I'm using Xcode 4.6 and target is iOS5+
Rough idea on how it might work. You'll need to manage the red line when the reusable cell content changes.
CGSize size = [cell.textLabel.text sizeWithFont:cell.textLabel.font];
CGFloat y = cell.contentView.frame.size.height / 2;
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(5,y,size.width, 3)];
line.backgroundColor = [UIColor redColor];
[cell.textLabel addSubview:line];
make some lines(like image, etc) above the tableViewCell
like [cell.contentView addSubView:$LINE_IMAGE_VIEW]
you can get the label's width like this
CGFloat width = cell.titleLabel.frame.size.width
then assign that width to custom line image.
This will strike through the whole cell. In case you need it to look like completed task:
CGSize size = cell.contentView.frame.size; // you'll draw the line in whole cell.
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(15,size.height / 2,size.width - 30, 1)];
line.backgroundColor = [UIColor grayColor]; // set your preferred color
[cell addSubview:line];
You may indicate some other value in CGRectMake instead of 15 - it's offset by X. In this case you'd better then decrease width by doubled value (in my case it's 15*2 = 30) in order it look nice.

UILabel sizeWithFont: problem. Clipping italic text

I have created a UILabel that displays a single large character. Even with clipsToBounds = NO; I still get clipping.
See link: http://img341.imageshack.us/img341/5310/screenshot20100814at243.png
I used the following code:
CGSize fBounds = [myLabel.text sizeWithFont:cFont];
To get what should be the bounding rectangle of the font. And the label is drawn with:
myLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 300)];
myLabel.clipsToBounds = NO;
myLabel.numberOfLines = 1;
myLabel.textAlignment = UITextAlignmentCenter;
myLabel.adjustsFontSizeToFitWidth = YES;
myLabel.minimumFontSize = 10;
myLabel.text = #"A";
myLabel.font = [UIFont fontWithName:#"CourierNewPSMT" size:300];
myLabel.textColor = [UIColor blackColor];
myLabel.backgroundColor = [UIColor colorWithRed:1 green:.5 blue:0 alpha:.5];
In the image below, the size returned from sizeWithFont is rendered by the semi-transparent blue rectangle overlay. As you can see, with an italic font (in this case Verdana-BoldItalic), the character extends past what sizeWithFont returns. Further, the UILabel's frame (the orange color) also clips the character. Thoughts? Maybe I could override some text drawing routine. Also, not sure if this is the same problem as here:
UIButton.titleLabel clipping text problem
Use attributed text + indent...
Looks like this is an apple problem. Ended up doing custom drawing with CoreText.

UIImageView blurs image

I have a really weird problem with UIImageView. I have an image (an RGB png) 45x45 pixels which I add to the view. I can see that image is blurred after added to the view. Here is the same image in the simulator (left) and in Xcode (right):
(source: partywithvika.com)
(source: partywithvika.com)
I have custom UIImageView class with this initWithImage code:
- (id) initWithImage:(UIImage*) image {
self = [super initWithImage:image];
self.frame = CGRectMake(0, 0, 45, 45);
self.contentMode = UIViewContentModeScaleAspectFit;
self.quantity = 1;
if (self) {
self.label = [[UITextField alloc]initWithFrame:CGRectMake(0,40,45,25)];
self.label.font = [UIFont systemFontOfSize:16];
self.label.borderStyle = UITextBorderStyleNone;
self.label.enabled = TRUE;
self.label.userInteractionEnabled = TRUE;
self.label.delegate = self;
self.label.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
self.label.textAlignment = UITextAlignmentCenter;
}
self.userInteractionEnabled = TRUE;
// Prepare 3 buttons: count up, count down, and delete
self.deleteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.deleteButton.hidden = NO;
self.deleteButton.userInteractionEnabled = YES;
self.deleteButton.titleLabel.font = [UIFont systemFontOfSize:20];
self.deleteButton.titleLabel.textColor = [UIColor redColor];
[self.deleteButton setTitle:#"X" forState:UIControlStateNormal];
[self.deleteButton addTarget:self action:#selector(deleteIcon:) forControlEvents:UIControlEventTouchUpInside];
self.upCountButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.upCountButton.hidden = NO;
self.upCountButton.userInteractionEnabled = YES;
[self.upCountButton setTitle:#"+" forState:UIControlStateNormal];
[self.upCountButton addTarget:self action:#selector(addQuantity:) forControlEvents:UIControlEventTouchUpInside];
self.downCountButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.downCountButton.hidden = YES;
self.downCountButton.userInteractionEnabled = YES;
[self.downCountButton setTitle:#"-" forState:UIControlStateNormal];
[self.downCountButton addTarget:self action:#selector(removeQuantity:) forControlEvents:UIControlEventTouchUpInside];
return self;
}
I create it like this:
UIImage *desertIcon = [UIImage imageNamed:#"desert.png"];
IconObj *desertIconView = [[IconObj alloc] initWithImage:desertIcon];
desertIconView.center = CGPointMake(265,VERTICAL_POINT_ICON);
desertIconView.type = [IconObj TYPE_DESERT];
[self.view addSubview:desertIconView];
[desertIconView release];
Why would the displayed image be so than the one stored in a file?
In general, everything you do on iPhone with UIKit should be pixel-aligned. Problems with pixel alignment usually manifest as blurriness (this is especially true with text and images). This is why when I find blurry view, I first check if I'm setting the center property. When you set center, the frame's x, y, height and width are adjusted around that center point... frequently resulting in fractional values.
You could try using CGRectIntegral on the frame as shown:
desertIconView.center = CGPointMake(265,VERTICAL_POINT_ICON);
desertIconView.frame = CGRectIntegral(desertIconView.frame);
This may work, but if it doesn't, try setting the frame manually, without using center property to ensure that no values are fractional.
Edit: Whoops! Didn't notice that the OP had answered his own question... I'll leave this up for informational reasons anyway.
I had this problem and it was driving me nuts. After some investigation it turned out that my image was smaller than the frame, and hence the scaling up blurred it. Once I had put in higher resolution images the problem is gone.
Make sure your image size is greater than your UIImageView frame size.
Your IconObj is 45 pixels wide. You move your IconObj center to 265 which makes its frame to (242.5, VERTICAL_POINT_ICON - 25*0.5, 45, 25). Image will always be blur if some of frame parameter is not integer.
Solution, calculate the frame parameter yourself (don't use center). And always make it integer (cast to NSInteger, use ceil, floor, or round).
desertIconView.frame = CGRectMake((NSInteger)(265 - 45*0.5),
(NSInteger)(VERTICAL_POINT_ICON - 25*0.5),
45, 25);
What I ended up doing is loading bigger picture into 45x45 UIImageView, of course with
contentMode = UIViewContentModeScaleAspectFit;
I just had the same problem. First I thought wtf do I need glasses?
Then I realized it´s just not possible to center an image (or label) when you give it an odd number. You need to resize your image to e.g. 46*46 if you want to center it and stay sharp.
Or you can leave it at 45*45 but then you need to decide whether you want your image to be mal-centered 1 pixel to the right, or 1 pixel to the left. (or leave it blurry).
Try to align your IconObj view at screen pixels. If it's really 45x45 then you should set the center to something like CGPointMake(x + 0.5f, y + 0.5f).
You should also double check image size in pixels (e.g in Preview.app Command-I).
complete source for the offset problem:
contentImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
UIImage *cImage = [UIImage imageNamed:image];
self.contentImage.image = cImage;
[self.contentImage setFrame:CGRectMake(0, 0, cImage.size.width, cImage.size.height)];
CGFloat offset = 0.0f;
if ( ( (int)cImage.size.width % 2 ) && ( (int)cImage.size.height % 2 ) ) {
offset = 0.5f;
}
[self.contentImage setCenter:CGPointMake(256.0f + offset, 256.0f + offset)];