20

I am adding a UILabel instance as a subview of my custom UITableViewCell instance's contentView.

When I select the cell, the row is highlighted blue, except for the background of the label. The label text is sharp.

When I set the label and content view backgroundColor property to [UIColor clearColor], the label text becomes blurry.

How do I set the label background color to be clear, to allow the row highlight to come through, while still keeping the label text sharp?

One suggestion I read elsewhere was to round the label's frame values, but this did not have any effect.

CODE

Here is a snippet of my custom UITableViewCell subview's -setNeedsLayout method:

UILabel *_objectTitleLabel = [[UILabel alloc] initWithFrame:CGRectNull];
_objectTitleLabel.text = [self.awsObject cleanedKey];
_objectTitleLabel.font = [UIAppDelegate defaultObjectLabelFont];
_objectTitleLabel.highlightedTextColor = [UIColor clearColor]; //[UIAppDelegate defaultLabelShadowTint];
_objectTitleLabel.backgroundColor = [UIColor clearColor]; //[UIAppDelegate defaultWidgetBackgroundTint];
_objectTitleLabel.frame = CGRectMake(
        kCellImageViewWidth + 2.0 * self.indentationWidth,
        0.5 * (self.tableView.rowHeight - 1.5 * kCellLabelHeight) + kCellTitleYPositionNudge,
        contentViewWidth,
        kCellLabelHeight
);
_objectTitleLabel.frame = CGRectIntegral(_objectTitleLabel.frame);
_objectTitleLabel.tag = kObjectTableViewCellTitleSubviewType;
//NSLog(@"_objectTitleLabel: %@", NSStringFromCGRect(_objectTitleLabel.frame));
[self.contentView addSubview:_objectTitleLabel];
[_objectTitleLabel release], _objectTitleLabel = nil;

...

self.contentView.backgroundColor = [UIAppDelegate defaultWidgetBackgroundTint]; 
self.contentView.clearsContextBeforeDrawing = YES;
self.contentView.autoresizesSubviews = YES;
self.contentView.clipsToBounds = YES;
self.contentView.contentMode = UIViewContentModeRedraw;
Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345

9 Answers9

35

The issue is sub-pixel rendering, which occurs when your origin (which is a float value) has a non-zero fractional component. Round to the nearest whole number and you should be fine.

Stuart Carnie
  • 5,458
  • 1
  • 29
  • 27
  • I am already setting the frame to integer values: `_objectTitleLabel.frame = CGRectIntegral(_objectTitleLabel.frame)` – Alex Reynolds Jan 23 '10 at 00:31
  • 1
    And you are still seeing an issue with blurry renders? What about your parent view(s) - are they too positioned integrally? – Stuart Carnie Jan 27 '10 at 16:44
  • 4
    Be warned: This problem also arises when setting the `center` of a view with odd width and/or height. – mvds Dec 22 '10 at 16:41
  • 1
    This answer should be marked as the correct answer to this question, and setting the center is a great way to cause this issue. – Jessedc Feb 04 '11 at 01:15
  • Had the same problem, but for me it didn't have anything to do with an odd width or height. I solved it by calling `floor()` on both `center.x` and `center.y`. – hkatz Jun 05 '11 at 21:25
  • 1
    `#define CGPointIntegral(point) CGPointMake((int)point.x,(int)point.y)` is a quick macro to cast CGPoint members to integers. – Andrew Feb 06 '12 at 02:16
  • Thank you, that saves a *lot* of time – roplacebo Apr 03 '13 at 11:58
9

In my case, having set shouldRasterize = YES on the CGLayer of the view containing the UILabel was the culprit. Removing that line made the text nice and crisp.

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165
7

Ok found the problem, Make sure your parent view's coordinates are rounded as well.

Gavin Miller
  • 43,168
  • 21
  • 122
  • 188
user281300
  • 1,427
  • 2
  • 19
  • 31
2

Setting shouldRasterize to YES may introduce blurriness. Set the rasterization scale and that should eliminate the blurriness. [self.layer setRasterizationScale:[[UIScreen mainScreen] scale]];

Shirish Kumar
  • 1,532
  • 17
  • 23
2

I ran into this problem myself today, and read somewhere that non-integer values for the origin and size of the UILabel's frame can cause this (I know they're floats, but you know what I mean). There has got to be a more elegant solution, but this quick hack appears to have solved the problem for me:

self.valueLabel.frame = CGRectMake((int) frame.origin.x, (int) frame.origin.y, (int) frame.size.width, (int) frame.size.height);

If you find a better solution, please let me know, I'd love to replace this hack with something a bit more tasteful.

Martin Gunnarsson
  • 159
  • 1
  • 1
  • 11
2

Another cause of garbled/blurry text is cell reuse. If you are de-queuing a reusable cell then it may redraw with different dimensions somewhere else and again be re-used when it gets to your cell with the garbled text.

To ensure the cells are unique be sure to allocate a new cell for the indicies where the text is garbled, and mark that UITableViewCell instance with a different reuse identifier. This is only practical of course if you're dealing with a very small number of cells and if you know exactly which cells are causing problems.

1

Sometimes the reason for the blurriness you have mentioned can be that labels's frame is beyond the cell frame. Even if you see all of your text you have put inside the label on your cell, the actual label size can be bigger than the cell frame.

To check if that is the reason for the effect you see I would suggest to check/print all the data you have about labels size/location after it is instantiated and than check in the delegate method tableView:heightForRowAtIndexPath: that this fit into the cell height you are returning for the cell. Hope it will help in your case.

anyab
  • 359
  • 5
  • 11
1

Use round(); C functions are provided for a reason.

#define roundCGRectValues (frame) \
frame = CGRectMake(round(frame.origin.x),round(frame.origin.y),round(frame.size.width),round(frame.size.height));

All you need.

gauravk92
  • 59
  • 3
1

Does -setNeedsLayout get called even for dequeued reusable cells? If so, the cell will already have the label added to the content view, and you will draw it twice, making it blurry. You can inefficiently solve this by removing all of the content view's subviews before you add your subview:

for (UIView *subview in [[self contentView] subviews]) {
     [subview removeFromSuperview];
}

A better solution would be to provide properties on your cell subclass to let you modify the content of a reused cell as-needed, rather than rebuilding its view hierarchy from scratch.

lemnar
  • 4,063
  • 1
  • 32
  • 44