How could you make a uilabel wrap around an image (like shown) - ios

How could you achieve this effect:
Maybe some sort of NSAtributedString?
I have thought of hacky ways to just add spaces, but it needs to do it dynamically based on the width of the image.
Any ideas?
NOTE happily you can do this very easily with UITextView:
https://stackoverflow.com/a/20033752/294884
this question is about UILabel.

Add image in your label with text as below code:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"Here is some text that is wrapping around like an image"];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:#"first.jpg"];
NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];
[attributedString insertAttributedString:attrStringWithImage atIndex:0];
[_lbn setAttributedText:attributedString];
Your OUTPUT :

You can use an NSAttributedString with an NSTextAttachment
NSTextAttachment *attachment = [[NSTextAttachment alloc]init];
[attachment setImage:<#UIImage#>];
NSAttributedString* icon = [NSAttributedString attributedStringWithAttachment:attachment];
[attributedString insertAttributedString:icon atIndex:<#index#>];
but it will only insert the image on one line, so it wont have multiple lines down the side of it (like a newspaper article), so its only useful for small images that fit on one line (sort of like how you have it in your question i guess)

Related

How to size a symbol image in an attributed string

I have a label where I am trying to put a symbol image at the start of the label and then some text after it. This works, but the symbol image never changes size. It doesn't matter what size I provide in the UIImageSymbolConfiguration, it stays small. If I take this code and put the image in a UIImageView, then the image gets larger as expected. Is there something wrong with anything I am doing here related to the symbol image configuration?
UILabel *label = [[UILabel alloc] init];
NSString *title = #"Some Text";
label.adjustsFontForContentSizeCategory = YES;
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#" %#", title] attributes:#{
NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody],
NSForegroundColorAttributeName: [UIColor labelColor]
}];
UIImageSymbolConfiguration *configuration = [UIImageSymbolConfiguration configurationWithFont:[UIFont preferredFontForTextStyle:UIFontTextStyleLargeTitle]];
UIImage *squareImage = [[UIImage systemImageNamed:#"square.fill" withConfiguration:configuration] imageWithTintColor:[UIColor systemBlueColor]];
NSTextAttachment *imageAttachment = [NSTextAttachment textAttachmentWithImage:squareImage];
[string insertAttributedString:[NSAttributedString attributedStringWithAttachment:imageAttachment] atIndex:0];
label.attributedText = string;
I stumbled upon the same issue as I was building a similar feature today. It seems that symbols work slightly differently when embedded in text attachments: it's the font set on the attributed string that determines the size, not the configuration of the symbol itself.
With this in mind, you simply need to make sure the range of the icon in the attributed string has a font set:
UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
[string addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 1)];
Note that you'll still need to configure the symbol if you intend to render using a different color. In this case, attributed strings will ignore the NSForegroundColorAttributeName attribute when rendering the symbol (resulting in a blank, zero-width symbol). I suspect this is because symbols have hierarchical colors, but I might be wrong.

Only first NSParagraphStyle applied in NSAttributedString

Goal is to have a single NSAttributedString with a larger line height between paragraphs than within a paragraph, a fairly simple and common use case it seems to me. Here's my code:
NSMutableParagraphStyle *firstParagraphStyle = [[NSMutableParagraphStyle alloc] init];
firstParagraphStyle.lineHeightMultiple = 3.0;
NSMutableParagraphStyle *secondParagraphStyle = [[NSMutableParagraphStyle alloc] init];
secondParagraphStyle.lineHeightMultiple = 1.0;
NSAttributedString *title = [[NSAttributedString alloc] initWithString:#"Title"
attributes:#{NSParagraphStyleAttributeName: firstParagraphStyle}];
NSAttributedString *bodyTop = [[NSAttributedString alloc] initWithString:#"\u2029Body 1"
attributes:#{NSParagraphStyleAttributeName: secondParagraphStyle}];
NSAttributedString *bodyBottom = [[NSAttributedString alloc] initWithString:#"\u2029Body 2 line 1\u2028Body 2 line 2"
attributes:#{NSParagraphStyleAttributeName: secondParagraphStyle}];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:title];
[attributedString appendAttributedString:bodyTop];
[attributedString appendAttributedString:bodyBottom];
All four lines end up with the same line spacing of 3.0. In fact, when I remove the attributes dictionary entirely and simply do:
NSAttributedString *title = [[NSAttributedString alloc] initWithString:#"Title"];
NSAttributedString *bodyTop = [[NSAttributedString alloc] initWithString:#"\u2029Body 1"];
NSAttributedString *bodyBottom = [[NSAttributedString alloc] initWithString:#"\u2029Body 2 line 1\u2028Body 2 line 2"];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:title];
[attributedString appendAttributedString:bodyTop];
[attributedString appendAttributedString:bodyBottom];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:firstParagraphStyle
range:NSMakeRange(0, 1)];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:secondParagraphStyle
range:NSMakeRange(1, attributedString.length - 1)];
it still renders all three paragraphs using line height multiple of 3.0. It seems that whatever the first paragraph style I apply to the string is, that's the one that applies to all subsequent lines and paragraphs!
Why doesn't using the special paragraph separator character \u2029 as Apple suggests here allow for more than one paragraph style within a single NSAttributedString? I'd prefer not to break into multiple UILabels.
Thanks in advance to anyone with deep Core Text knowledge on this subject.
Ended up getting this working. Turns out when I set alignment on the subsequent UILabel to .textAlignment = NSTextAlignmentCenter that messed up the paragraph style for the entire attributedText.
So the lesson is: If you're using multiple paragraph styles, don't set any corresponding properties on the UILabel or your behavior will be clobbered by the first paragraph style the label sees, even when the properties aren't related (e.g. line height and text alignment).

Horizontal spacing for NSTextAttachment

I'm trying to display an image in a UITextField using NSTextAttachment, but I want some horizontal space between the image and the text. However, when add the NSKernAttributeName attribute to the attributed string as follows, it resets the height of the attachment to the same height as the surrounding text.
var str = NSMutableAttributedString(attributedString: NSAttributedString(attachment: imageAttachment))
str.addAttribute(NSKernAttributeName, value: 10, range: NSRange(location: 0,length: 1))
Is there another way to add horizontal space between the image and the text?
The most direct way is in string start set a few space :
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
[attachment setImage:[UIImage imageNamed:#"dest_poi_content_quotation"]];
NSString *reviewText = [NSString stringWithFormat:#" %#", review.text];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:reviewText];
NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:attachment];
[attributedString insertAttributedString:attrStringWithImage atIndex:0];
[self.lblComment setAttributedText:attributedString];

ios7 custom interaction with nstextattachment in uilabel

I have an NSTextAttachment with an image in a UILabel and I would like to perform a custom behaviour when clicking on this attachment.
UITextViewDelegate provides an handy method
textView:shouldInteractWithTextAttachment:inRange:
But it can only be used if I'm using UITextView.
Is there any solution if Im using UILabel?
Thanks!
The text attachment becomes part of the model and is treated like a character, so try adding a link to the range of your attachment.
Like this:
NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithData:nil ofType:nil];
attachment.image = [UIImage imageNamed:#"myImage"];
NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:attachment];
NSMutableAttributedString *mutableImageString = [imageString mutableCopy];
[mutableImageString addAttribute:NSLinkAttributeName value:#"http://stackoverflow.com" range:NSMakeRange(0, mutableImageString.length)];

Underlining a certain portion of a UILabel

I need to underline a certain portion of a UILabel as the title suggests. For example: Please click ESPNSoccernet to read the latest Football News. I would like to underline the word ESPNSoccernet. This is because I want it to be clickable and it need to link to the website.
Need some guidance on doing this. If there is another way, do tell me...
for ios 6, you can use AttributedStrings
NSMutableAttributedString *yourString = [[NSMutableAttributedString alloc] initWithString:#"Please click ESPNSoccernet to read the latest Football News."];
[yourString addAttribute:NSUnderlineStyleAttributeName
value:[NSNumber numberWithInt:1]
range:(NSRange){0,25}];
label.attributedText = [yourString copy];
you can also use a 3rd party UILable library TTTAttributedLabel.
In Xcode:
Select the label and choose identity inspector.
In text choose Attributed instead of plain.
Now Select the portion of text you want to underline.
Select font and choose underline in fonts style.
There you go.
Swift 2.0:
1) Make a nsmutablestring with underline attribute and add to sampleLabel's text.
2) Add a tap gesture to sampleLabel and associate a method for further action.
override func viewDidLoad() {
super.viewDidLoad()
let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapResponse:")
tapGesture.numberOfTapsRequired = 1
sampleLabel.userInteractionEnabled = true
sampleLabel.addGestureRecognizer(tapGesture)
}
func tapResponse(recognizer: UITapGestureRecognizer) {
print("tap")
}
UILabel is only capable of displaying plain text strings (in iOS 6 it can now also display NSAttributedStrings, but this will not work in older iOS versions, so it is best not to rely on this), so you will not be able to do this with a label.
You can look at TTTAttributedLabel for displaying attributed text (so you can add underlines and other formatting), but you will not be able to add hyperlinks with this class.
The options you have for a clickable segment of the string are basically:
Use a plain UILabel and overlay a UIButton over the part that you want to be clickable, or
Use TTTAttributedLabel to achieve the underline effect, and a UITapGestureRecognizer to detect and handle taps (note that this will capture taps on the entire label, not just the underlined part).
For iOS 6:
UILabel *label = [[UILabel alloc] init];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"Tap here to read the latest Football News."];
[string addAttribute:NSUnderlineStyleAttributeName value:#(1) range:NSMakeRange(4, 4)];
label.attributedText = [string copy];
For earlier iOS versions as well as iOS 6:
TTTAttributedLabel *label = [[TTTAttributedLabel alloc] init];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"Tap here to read the latest Football News."];
[string addAttribute:NSUnderlineStyleAttributeName value:#(1) range:NSMakeRange(4, 4)];
label.text = [string copy];
Then add a gesture recogniser and implement handleTap::
UITapGestureRecognizer *recogniser = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[label addGestureRecognizer:recogniser];
- (void)handleTap:(UITapGestureRecognizer *)recogniser {
// Handle the tap here
}
Well, i have done the same thing like this:
Make a custom button with text: ESPNSoccernet, and background clearColor
Add a label as a subview with height 1 and some background color to this button, such that "ESPNSoccernet" looks underlined.
Put the remaining text in a label adjacent to this button, so that it looks like a whole text.
Hope it helps!
Note: if you r doing only >iOS 6.0, you might wanna check the other answers.
If this app for ios 6 or later version in that case you can use NSMutableAttributedString
NSMutableAttributedString *labelText = [[NSMutableAttributedString alloc] initWithString:#"Hello this is demmy label for testing"];
[labelText addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:1]
range:(NSRange){10,10}];
label.attributedText = labelText;
for less version you can use like this..
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 116, 171, 20)];
label.text = #"Hello this is demmy label for testing";
label.textColor = [UIColor whiteColor];
label.font = [UIFont systemFontOfSize:16];
[self.view addSubview:label];
//underline code
CGSize expectedLabelSize = [[m_BCListArray objectAtIndex:tagcount] sizeWithFont:label.font constrainedToSize:label.frame.size lineBreakMode:UILineBreakModeWordWrap];
UIView *viewUnderline=[[UIView alloc] init];
viewUnderline.frame=CGRectMake((label.frame.size.width - expectedLabelSize.width)/2, expectedLabelSize.height + (label.frame.size.height - expectedLabelSize.height)/2, expectedLabelSize.width, 1);
viewUnderline.backgroundColor=[UIColor whiteColor];
[self.view addSubview:viewUnderline];
The following code snippet produces desired result :
NSDictionary *dictAttribute = #{NSForegroundColorAttributeName:[UIColor redColor],NSUnderlineStyleAttributeName:#1};
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:#"Please click ESPNSoccernet to read the latest Football News." attributes:dictAttribute];
lblText.attributedText = attrString;

Resources