how to resize an image or done as a NSAttributedString NSTextAttachment (or set its initital size)
Look at subclassing NSTextAttachment
and implementing the NSTextAttachmentContainer
methods to return different sizes based on the text container supplied. By default, NSTextAttachment
just returns the size of the image it is provided with.
Swift iOS -How to Set NSTextAttachment Content Mode to Aspect Fit?
I followed @Maciej Swic's answer
Resize NSTextAttachment Image
For some reason I couldn't extend the NSTextAttachment class so I added it to the bottom of the class I was using it in. I removed the bounds property that I used in my question and used his function instead. It's on #4, the second line:
class MyController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
// #1. Define dict attribute for string
let bold17 = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 17)]
// #2. Create "hello" string and add the dict attribute to it
let helloStr = NSAttributedString(string: "Hello\n\n", attributes: bold17)
// #3. Create NSTextAttachment
let textAttachment = NSTextAttachment()
// #4. Add image to the textAttachment then set it's bounds
textAttachment.image = UIImage(named: "world_PDF")
textAttachment.setImageHeight(height: 200) // <----HIS ANSWER HERE
// #5. Set image as NSAttributedString
let worldImage = NSAttributedString(attachment: textAttachment)
// #6. Create NSMutableString to
let mutableAttributedString = NSMutableAttributedString()
// #7. Append the "hello" string and the "world" image to each other using the mutableAttributedString object
mutableAttributedString.append(helloStr)
mutableAttributedString.append(worldImage)
// #8. Set the mutableAttributedString to the textView then center it
textView.attributedText = mutableAttributedString
textView.textAlignment = .center
}
}
extension NSTextAttachment {
func setImageHeight(height: CGFloat) {
guard let image = image else { return }
let ratio = image.size.width / image.size.height
bounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: ratio * height, height: height)
}
}
Resize an image that is used in NSAttributedString
Oh right, so NSTextAttachment
doesn't have image views... ah... Right well then another idea comes to mind. How about reszing the UIImage
data and then passing that image to the NSTextAttachment
, like in this post:
https://stackoverflow.com/a/2658801/4657588
Make use of this method to resize the image accordingly:
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Center NSTextAttachment image next to single line UILabel
You can change the rect by subclassing NSTextAttachment
and overriding attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex:
. Example:
- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex {
CGRect bounds;
bounds.origin = CGPointMake(0, -5);
bounds.size = self.image.size;
return bounds;
}
It's not a perfect solution. You have to figure out the Y-origin “by eye” and if you change the font or the icon size, you'll probably want to change the Y-origin. But I couldn't find a better way, except by putting the icon in a separate image view (which has its own disadvantages).
NSTextAttachment images are not dynamic (light/dark mode)
I think that's unfortunately the normal behavior, but I considered it as a forgotten feature non-dev by Apple.
The only way I got currently, is to listen to func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
to detect the mode change.
Then, you can either reconstruct your NSAttributedString
, or enumerate over it and update it when needed.
With a enumeration, ie update only what's needed, and not regenerate the whole NSAttributedString
:
In your initial attachment creation:
let attachment = NSTextAttachment(image: asset.image(with: traitCollection))
let attachmentCharacter = NSAttributedString(attachment: attachment)
Side note:
I used asset.image(with: traitCollection)
instead of image1
, else when starting with dark mode, your image will be of light mode instead. So this should set the correct image.
Then, I'd update it with:
func switchAttachment(for attr: NSAttributedString?) -> NSAttributedString? {
guard let attr = attr else { return nil }
let mutable = NSMutableAttributedString(attributedString: attr)
mutable.enumerateAttribute(.attachment, in: NSRange(location: 0, length: mutable.length), options: []) { attachment, range, stop in
guard let attachment = attachment as? NSTextAttachment else { return }
guard let asset = attachment.image?.imageAsset else { return }
attachment.image = asset.image(with: .current)
mutable.replaceCharacters(in: range, with: NSAttributedString(attachment: attachment))
}
return mutable
}
And update when:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
label.attributedText = switchAttachment(for: label.attributedText)
}
Related Topics
Launch Image Not Showing Up in iOS Application (Using Images.Xcassets)
Nsdateformatter and Current Language in iOS11
How to Prevent Keyboard Push Up Webview at iOS App Using Phonegap
Xcode 4/iOS - Send an Email Using Smtp from Inside My App
Swiftui: What Is @Appstorage Property Wrapper
Keyboard and Cursor Show, But I Can't Type Inside Uitextfields and Uitextviews
Expand Uilabel Inside Uitableview with "More" Button Like Instagram
Custom Font Not Working Programmatically in Swift
Centering Mkmapview on Spot N-Pixels Below Pin
How to Use Cgaffinetransformmakerotation
Ios: Custom Permission Alert View Text
Nib But Didn't Get a Uitableview
How to Keep a Round Imageview Round Using Auto Layout
Type 'Any' Has No Subscript Members (Firebase)