Custom Icon For UITextView in ObjectiveC - ios

I want to create a UITextView (or UITextField) with custom icon.
I know how to add a UIImageView to the UITextView but the cursor ignore the UIImageView and I cant edit or delete the icon (the UIImageView).
What is the best way to do it?
I know that it is possible because apple use it in the iMessage (image attached) and there is another application name "kik" with the same behavior.

Try this gever ;) :
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"before after"];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:#"download.jpeg"];
CGFloat oldWidth = textAttachment.image.size.width;
CGFloat scaleFactor = oldWidth / (self.textField.frame.size.width - 10);
textAttachment.image = [UIImage imageWithCGImage:textAttachment.image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];
[attributedString replaceCharactersInRange:NSMakeRange(6, 1) withAttributedString:attrStringWithImage];
self.textField.attributedText = attributedString;

Related

NSTextAttachment not showing

I am unable to get the NSTextAttachment to show for the NSAttributedString returned in the function below.
- (NSAttributedString *) tokenString:(NSUInteger) tokens
{
CGFloat size = 20;
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.bounds = CGRectMake(0,0,size,size)
attachment.image = [[UIImage imageNamed:#"ContestTokenSmall"] imageScaledToSize:CGSizeMake(size, size)];
NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#" %ld", (long)tokens] attributes:[self attributedStringAttributes]];
[str insertAttributedString:attachmentString atIndex:0];
return str;
}
The label I'm using is as follows:
- (UILabel *) tokenLabel
{
if (_tokenLabel == nil)
{
_tokenLabel = [[UILabel alloc] init];
_tokenLabel.translatesAutoresizingMaskIntoConstraints = NO;
_tokenLabel.font = [UIFont zbd_boldFontWithSize:13.0];
_tokenLabel.textColor = UIColor.whiteColor;
[_tokenLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[_tokenLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[_tokenLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[_tokenLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
}
return _tokenLabel;
}
I've tried removing the NSTextAttachment bounds, changing/removing image resizing, and using a different image but nothing I do seems to make an image appear in the label.
Is there something wrong in the code above? Is there a property I need to set in the label to make the image show?
Thanks in advance!
EDIT
How I set the label:
self.tokenLabel.attributedText = [self tokenString:award.topBid];
Log of string:
2018-04-24 16:03:14.579429-0500 TestGame1[44243:1597097] {
NSAttachment = "<NSTextAttachment: 0x6040002c2e60>";
} 10{
NSColor = "UIExtendedGrayColorSpace 1 1";
NSFont = "<UICTFont: 0x7ff0df85ff10> font-family: \"Domus\"; font-weight: bold; font-style: normal; font-size: 13.00pt";
}
Also, I see an empty space where the image should be.
UPDATE 2
The image created with the code below will show in the attributed string, but still none of the pdf or png images loaded from Media.xcassets will show.
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor.redColor CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I figured it out. The problem was with [UIImage imageNamed:#"ContestTokenSmall"]. Since the image was located in the framework the this code is in, I needed to use
+ (nullable UIImage *)imageNamed:(NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection NS_AVAILABLE_IOS(8_0);
so that it would get the image from the correct bundle. I was getting the image from the framework's bundle while debugging and that is why the image would show in image views while not showing in the attributed string.

UIImage next to centered UITextField Placeholder Text

What would be the best approach for aligning a UIImage icon next to the centered placeholder text of a UITextField? Ex:
I have been attempting to replicate this for sometime now and can't seem to reach the desired effect.
I've tried using the LeftView of the UITextField however can't get this aligned next to the placeholder text (I thought about adding padding to the LeftView by changing it's frame but am unsure how I would obtain the values needed to align it next to the placeholder. There does not appear to be away to get the coordinates for the placeholder text.) . I've also tried to subclass UITextField but here am again unsure on how to obtain the proper coordinates.
You can attach images inside attributed strings using NSTextAttachment
Swift 3.0
txtField.textAlignment = .center
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "searchIcon")
attachment.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
let attachmentStr = NSAttributedString(attachment: attachment)
let myString = NSMutableAttributedString(string: "")
myString.append(attachmentStr)
let myString1 = NSMutableAttributedString(string: "Find a Location (Zip Code or Name)")
myString.append(myString1)
txtField.attributedPlaceholder = myString
Objective-C
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:#"searchIcon"];
attachment.bounds = CGRectMake(0, 0, 10, 10);
NSAttributedString *attachmentStr = [NSAttributedString attributedStringWithAttachment:attachment];
NSMutableAttributedString *myString = [[NSMutableAttributedString alloc] initWithString:#""];
[myString appendAttributedString:attachmentStr];
NSMutableAttributedString *myString1 = [[NSMutableAttributedString alloc] initWithString:#"Find a Location (Zip Code or Name)"];
[myString appendAttributedString:myString1];
txtField.attributedPlaceholder = myString;

Add Carousel View inside Textview

I am adding data into TextView through sqlite database. I have around 30 to 35 images to be added in it after some Para or Line of data, which i have done through NSTextAttachment. Now what i want to do is wherever there are more that 2 images i want it to be in Carousel View and remaining data after it. Have a look at my code. I tried the different way but not getting success. Any help will be much appreciated.
NSTextAttachment *textAttachment1 = [[NSTextAttachment alloc] init];
textAttachment1.image = [UIImage imageNamed:#"img1.png"];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:#"img2.png"];
NSTextAttachment *textAttachment2 = [[NSTextAttachment alloc] init];
textAttachment2.image = [UIImage imageNamed:#"img3.png"];
NSTextAttachment *textAttachment3 = [[NSTextAttachment alloc] init];
CGFloat oldWidth1 = textAttachment1.image.size.width;
CGFloat oldWidth = textAttachment.image.size.width;
CGFloat oldWidth2 = textAttachment2.image.size.width;
CGFloat scaleFactor1 = oldWidth1 / (self.textViewResearch.frame.size.width + 70);
CGFloat scaleFactor = oldWidth / (self.textViewResearch.frame.size.width + 70);
CGFloat scaleFactor2 = oldWidth2 / (self.textViewResearch.frame.size.width + 70);
textAttachment1.image = [UIImage imageWithCGImage:textAttachment1.image.CGImage scale:scaleFactor1 orientation:UIImageOrientationUp];
textAttachment.image = [UIImage imageWithCGImage:textAttachment.image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
textAttachment2.image = [UIImage imageWithCGImage:textAttachment2.image.CGImage scale:scaleFactor2 orientation:UIImageOrientationUp];
NSAttributedString *attrStringWithImage1 = [NSAttributedString attributedStringWithAttachment:textAttachment1];
NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];
NSAttributedString *attrStringWithImage2 = [NSAttributedString attributedStringWithAttachment:textAttachment2];
[attributedString replaceCharactersInRange:NSMakeRange(0, 0) withAttributedString:attrStringWithImage1];
[attributedString replaceCharactersInRange:NSMakeRange(13740, 0) withAttributedString:attrStringWithImage];
[attributedString replaceCharactersInRange:NSMakeRange(13741, 0) withAttributedString:attrStringWithImage2];
self.textView.attributedText = attributedString;
If I understood you correctly, you want to place an image inside a text view and let the text flow around it. Having more than 2 images you want to have a carousel, an instance of the class iCarousel.
Having a subview inside an instance of UITextView and letting the text float around it, is a known tasks. The easiest way seems to be to use the exclusion path of a text container like this:
// Get the dimension of the subview
iCarousel *subview = …;
UIBezierPath *subviewPath = [UIBezierPath bezierPathWithRect:subview.frame];
// Somewhere you should add it
UITextView *textView = …; // Wherever it comes from
[textView addSubview:subview];
// Let the text flow around it
UITextContainer *textContainer = textView.textContainer; // The text container is the region text is laid out in.
textContainer.exclusionPaths = [subviewPath]; // Do not lay out in this region.
Of course you have to change the exclusion region, whenever the frame of the subviews change.
A more flexible and more complex approach is to do the text layout your own. If the above approach does not work, let me know. I will add code for this.

iOS: How to adjust placement of adjacent UIView based on text in UILabel next to it

There are two UIImageView and two UILabel set up like the illustration above. Both UILabel's text will be populated via Web Data and could be any length.
When the "Something" label inevitably gets populated with something longer than "something", the UIImageView to it's immediate right needs to move to the right based on the amount of text inside the "something" label.
How would one go about doing this?
Although please use auto layouts, here is a programmatic way of handling this:
// Image before Something text
UIImageView *somethingImageView = [[UIImageView alloc] initWithFrame:CGRectMake(5.0, 10.0, 40, 40)];
CGFloat somethingLabelXM = 5.0;
NSString *somethingLabelText = #"Random Text";
CGFloat somethingLabelTextW = [somethingLabelText sizeWithFont:[UIFont systemFontOfSize:12.0] constrainedToSize:CGSizeMake(MAXFLOAT, 1000) lineBreakMode:NSLineBreakByTruncatingTail].width;
// Something text
UILabel *somethingLabel = [[UILabel alloc] initWithFrame:CGRectMake(somethingImageView.frame.origin.x + somethingImageView.frame.size.width + somethingLabelXM, somethingImageView.frame.origin.y, somethingLabelTextW, 40.0)];
somethingLabel.text = somethingLabelText;
UIImage *moreImage = [UIImage imageNamed:#"SomeImage"];
// Image after Something text
UIImageView *moreImageView = [[UIImageView alloc] initWithFrame:CGRectMake(somethingLabel.frame.origin.x + somethingLabel.frame.size.width + somethingLabelXM, somethingImageView.frame.origin.y, moreImage.size.width, moreImage.size.height)];
moreImageView.image = moreImage;
// More text
NSString *moreLabelText = #"Random Text";
CGFloat moreLabelTextW = [moreLabelText sizeWithFont:[UIFont systemFontOfSize:12.0] constrainedToSize:CGSizeMake(MAXFLOAT, 1000) lineBreakMode:NSLineBreakByTruncatingTail].width;
UILabel *moreLabel = [[UILabel alloc] initWithFrame:CGRectMake(moreImageView.frame.origin.x + moreImageView.frame.size.width + somethingLabelXM, somethingImageView.frame.origin.y, moreLabelTextW, 40.0)];
somethingLabel.text = moreLabelText;

Place an UIImage after an UILabel

I want to have an UILabel with a max width of 100 and after that an UIImage, how can I do that in interface builder? I want that if the text is shorter the label is less than 100 but the UIImage is right behind the label.
You can use NSTextAttachment class available from iOS 7.No need to play with the frame.
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:#"image.png"];
NSAttributedString *attachmentAttrString = [NSAttributedString attributedStringWithAttachment:attachment];
NSMutableAttributedString *str= [[NSMutableAttributedString alloc] initWithString:#"hello"];
[str appendAttributedString:attachmentAttrString];
myLabel.attributedText = str;
you can do it with code like this:
first init the label and the imageView
_label = [[UILabel alloc] initWithFrame:CGRectZero];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(label.frame.origin.x + label.frame.size.width, label.frame.origin.y, 30, 30)];
then when the label has text , you can calc the width of the label`s frame
CGSize size = [_label.text sizeWithFont:[UIFont boldSystemFontOfSize:15]];
CGFloat width = size.width > 100 ? 100 : size.width;
CGFloat height = size.height;
_label.frame = CGRectMake(0, 0, width, height);
I'd like to add my swift solution:
let label = UILabel()
let attributedString = NSMutableAttributedString(string: "Hello".uppercaseString)
let attachment = NSTextAttachment()
attachment.image = UIImage(named:"hello")
attributedString.appendAttributedString(NSAttributedString(attachment:attachment))
// use the following method to insert the image at any index
// attributedString.insertAttributedString(NSAttributedString(attachment:attachment), atIndex: 0)
label.attributedText = attributedString

Resources