22

I have a UILabel that I need to convert to a UITextView because reasons. When I do this, the text is not positioned the same, despite using the same (custom) font.

I found that if I set:

textView.textContainer.lineFragmentPadding = 0;
textView.textContainerInset = UIEdgeInsetsZero;

This gets the text very close, but if I superimpose the UITextView over top of the UILabel, I see the text positioning get farther apart with each new line.

Screen shot showing text drift.

The UILabel is green, the UITextView is black. This is using NSParagraphStyle to set min and max line height to 15.

I've played with setting the paragraph style and min/max line height, but I haven't been able to match it exactly. I'm not a printer, so I don't necessarily understand all of the font related terms in the documentation for NSLayoutManager and NSTextContainer and all that.

I only need to support iOS 7 and up.

I'm not going to switch to some crazy CoreText-based custom widget or use some random third party library. I'm okay with close enough if I have to. But it seems like there should be some combination of random properties to make them layout the same.

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222

2 Answers2

18

I took the solution for line spacing found at this link and applied it to your issue. I managed to get it incredibly close by adjusting the lineSpacing property. I tested with HelveticaNeue size 13 and managed to get it to line up as shown in the screen shot below.

textView.textContainer.lineFragmentPadding = 0;
textView.textContainerInset = UIEdgeInsetsZero;

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];

paragraphStyle.lineSpacing = -0.38;

NSDictionary *attrsDictionary =
@{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:13.0f],
 NSParagraphStyleAttributeName: paragraphStyle};

textView.attributedText = [[NSAttributedString alloc] initWithString:textView.text attributes:attrsDictionary];

Screen Shot

Community
  • 1
  • 1
Stonz2
  • 6,306
  • 4
  • 44
  • 64
  • Looks like workaround, but not a solution. It turns out, that boundingRectWithSize: for NSAttributedString returns size, that matches the size of how it is rendered by UITextView, but not UILabel. What if I need to use UILabel, but boundingRectWithSize's size doesn't correspond with it? – vahotm Apr 25 '15 at 08:07
  • @user2327139 I agree that it is more of a workaround than a solution. Regarding your question, I'm not entirely sure what you're asking, but if you have a new question, use the "Ask a Question" link. Include a link to this question if you think it would be helpful. – Stonz2 Apr 25 '15 at 15:24
  • If you use attributed strings for both the UILabel and the UITextView, you can make the line spacing be the same in both. No hacks needed. – phatmann Jan 22 '18 at 17:51
4

I've been able to successfully 'impersonate' a non-editable multiline UILabel (as it happens, in a UITableViewCell subclass) with an equivalent editable multiline UITextView using the following :

_textView = UITextView.new;
_textView.font = _label.font;
_textView.textColor = _label.textColor;
_textView.textAlignment = _label.textAlignment;
_textView.backgroundColor = UIColor.clearColor;
_textView.textContainer.lineFragmentPadding = 0;
_textView.textContainerInset = UIEdgeInsetsZero;

and to make it behave well when doing actual edits, add the following to your UITextViewDelegate:

- (void)textViewDidChange:(UITextView *)textView
{
    ...
    [textView scrollRangeToVisible:NSMakeRange(textView.text.length, 0)];
    [textView scrollRectToVisible:[textView caretRectForPosition:textView.endOfDocument] animated:NO];
}
tiritea
  • 1,229
  • 13
  • 18