Draw a line inside a UITextView - NSAttributedString

I want to draw a custom string inside a UITextView consisting of some text (using NSAttributedString )

Here is what I tried

 NSString *unicodeStr = [NSString stringWithFormat:@"%C%C%C", 0x00A0, 0x0009, 0x00A0]; //nbsp, tab, nbsp NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:unicodeStr]; NSRange strRange = NSMakeRange(0, str.length); NSMutableParagraphStyle *const tabStyle = [[NSMutableParagraphStyle alloc] init]; tabStyle.headIndent = 16; //padding on left and right edges tabStyle.firstLineHeadIndent = 16; tabStyle.tailIndent = -16; NSTextTab *listTab = [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentCenter location:40 options:@{}]; //this is how long I want the line to be tabStyle.tabStops = @[listTab]; [str addAttribute:NSParagraphStyleAttributeName value:tabStyle range:strRange]; [str addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:2] range:strRange]; 

But no matter what value I provide for the tab stop (in this case 40) and tailIndent (-16 here), the line only considers the title and covers the entire width of the UITextView (minus headIndent, of course).

EDIT . I'm sure the problem is that I am not using the correct Unicode characters (although they seem like a logical choice). If this gives someone a hint, if I add a space after the second nbsp, that is, towards the end, the tab will be limited to one tab length

+7
ios objective-c nsattributedstring
source share
2 answers

Is this your expected result?

enter image description here enter image description here

Can you try this:

 NSTextTab *listTab = [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentCenter location:self.textView.frame.size.width - tabStyle.firstLineHeadIndent + tabStyle.tailIndent options:@{}]; 

And this is the full code:

 - (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSString *unicodeStr = @"\n\u00a0\t\t\n"; NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:unicodeStr]; NSRange strRange = NSMakeRange(0, str.length); NSMutableParagraphStyle *const tabStyle = [[NSMutableParagraphStyle alloc] init]; tabStyle.headIndent = 16; //padding on left and right edges tabStyle.firstLineHeadIndent = 16; tabStyle.tailIndent = -70; NSTextTab *listTab = [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentCenter location:self.textView.frame.size.width - tabStyle.headIndent + tabStyle.tailIndent options:@{}]; //this is how long I want the line to be tabStyle.tabStops = @[listTab]; [str addAttribute:NSParagraphStyleAttributeName value:tabStyle range:strRange]; [str addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:2] range:strRange]; NSAttributedString *htmlStr = [[NSAttributedString alloc] initWithData:[@"<h1>Lorem ipsum dolor sit er elit lamet</h1>" dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil]; [str insertAttributedString:htmlStr atIndex:0]; [str appendAttributedString:htmlStr]; self.textView.attributedText = str; } 
+2
source share

Here is what I did to solve the same problem. It uses a subclass of NSTextTab :

 import UIKit class RightAnchoredTextTab : NSTextTab { weak var textContainer : NSTextContainer! required init(textAlignment alignment: NSTextAlignment, location loc: CGFloat, options: [String : AnyObject], textContainer aTextContainer : NSTextContainer) { super.init(textAlignment: alignment, location: loc, options: options) textContainer = aTextContainer } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override var location: CGFloat { get { return textContainer.size.width-textContainer.lineFragmentPadding*2-super.location } } } 

And similar bits similar to other solutions:

 func horizontalLine(indent : CGFloat = 30, width : CGFloat = 1) -> NSAttributedString { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.tabStops = [] paragraphStyle.addTabStop(NSTextTab(textAlignment: .Left, location: indent, options: [:])) paragraphStyle.addTabStop(RightAnchoredTextTab(textAlignment: .Right, location: indent, options: [:], textContainer : textView.textContainer)) paragraphStyle.alignment = .Left let attributes = [NSParagraphStyleAttributeName : paragraphStyle, NSStrikethroughStyleAttributeName : width] textView.backgroundColor = UIColor.yellowColor() let ZeroWidthNonBreakingSpace = "\u{FEFF}" return NSAttributedString(string: "\t\(ZeroWidthNonBreakingSpace)\t\(ZeroWidthNonBreakingSpace)\n", attributes: attributes) } 

A few notes:

  • It will probably work with only one square text container.
  • NSTextContainer has lineFragmentPadding . If you all wondered why you need to fall back to the right alignment tab by 10, this is: the default value is 5.
  • A text prefix with \n means that there was no strikethrough. I do not know why.
  • This solution works with rotations, etc., when the UITextView calls NSTextTab.location again when the borders change.
0
source share

All Articles