Insets to UIImageView?
Asked Answered
E

8

64

I would like to achieve :

  • Scale to fill mode of image view
  • Insets to UIImageView so that image does not meet the edges of the UIImageView

Bottomline: I want to increase the touch area of the UIImageView without stretching the image beyond certain size.

Is it possible through storyboard ? If not can anyone tell how to do it programmatically ?

I can achieve similar functionality through a UIButton and setting image inset through storyboard but I can't find any such thing with UIImageView.

Excision answered 31/8, 2015 at 5:12 Comment(3)
Are you considering changing the size of the image while in runtime without actually affecting the original image? will that do?Intisar
That would change the scale and pixelate your image if your imageview is low, instead there is a turnaround which you can try, if u are willing to reconsider i can post an answerIntisar
you can post I'll see if it works ..Excision
E
33

Using the method given here :

UIImage *image= [MyUtil imageWithImage:[UIImage imageNamed:@"MyImage"] scaledToSize:CGSizeMake(80, 80)];

UIImageView* imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imgView.contentMode = UIViewContentModeCenter;
[imgView setImage:image];

Now your insets become 100-80 i.e. 20 .

This is a workaround to provide insets to an UIImageView. Better answers are welcomed.

Excision answered 31/8, 2015 at 9:7 Comment(0)
J
91

You can add inset to UIImage instead of UIImageView.

Swift 4

let imageView = UIImageView() 
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "example")?.withAlignmentRectInsets(UIEdgeInsets(top: -4, left: 0, bottom: -4, right: 0))
Jeanejeanelle answered 3/2, 2018 at 8:29 Comment(8)
I corrected the syntax but this actually doesn't workSnobbish
Works super well. I found I had to put negative insets to make my image smaller though.Gold
Looks good on paper, but has no effect for me, whether negative or positive values for the UIEdgeInset arguments. And yes, I'm using contentMode .scaleAspectFill.Elbert
I just tested it again, it appears it has no effect when you are setting imageView frame manually. It works when imageView is set using auto layout.Jeanejeanelle
I'm using constraints.Elbert
This will change the UIImageView's constraints.Interrogator
I ran in the problem that this solution didnt work for me. The problem was that my image had top, bottom, trailing and leading constrains to its parent. The fix was to have only "align center x" and "align center y" contains to be available for this imageView. So the imageView can compute its own instrict size, taking the insets into count.Auriol
This has strange behavior for my use case. I wanted a rounded grey square background (48px) with an inset image in the center (24px). I was using constraints for layout. For some reason this messes with the corner radius and background size. Would recommend just using a UIView and embedded UIImageView rather than messing with this property.Snoop
E
33

Using the method given here :

UIImage *image= [MyUtil imageWithImage:[UIImage imageNamed:@"MyImage"] scaledToSize:CGSizeMake(80, 80)];

UIImageView* imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imgView.contentMode = UIViewContentModeCenter;
[imgView setImage:image];

Now your insets become 100-80 i.e. 20 .

This is a workaround to provide insets to an UIImageView. Better answers are welcomed.

Excision answered 31/8, 2015 at 9:7 Comment(0)
K
28

It looks like you want to have a touchable imageView, so why not using an UIButton with image and imageEdgeInsets?

UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
[b setFrame:someFrame];
[b setImage:img forState:UIControlStateNormal];
b.imageEdgeInsets = UIEdgeInsetsMake(20, 20, 20, 20);
[b addTarget:self action:@selector(imageClicked:) forControlEvents:UIControlEventTouchUpInside];
Kwakiutl answered 31/8, 2015 at 8:18 Comment(3)
Awesome I love the idea of using button to add insets functionality to the image. +1Sprain
This works fine until iOS changes the look/feel of buttons again and suddenly puts borders or backgrounds in them so they don't just look like unadorned images anymore.Chrischrism
definitely a solution. nice!Extrapolate
R
26

My Code

  • minus inset: smaller image
  • plus inset: larger image

Swift4

private lazy var imageView: UIImageView = {
    let view = UIImageView()
    view.contentMode = .scaleAspectFit
    let insetValue: CGFloat = -8
    view.image = image.withAlignmentRectInsets(UIEdgeInsets(top: insetValue, left: insetValue, bottom: insetValue, right: insetValue))
    return view
}()
Retrochoir answered 21/11, 2018 at 16:13 Comment(0)
H
22

Do not suffer, try this:

After trying for a while I found this solution:

extension UIImage {

    func withInset(_ insets: UIEdgeInsets) -> UIImage? {
        let cgSize = CGSize(width: self.size.width + insets.left * self.scale + insets.right * self.scale,
                            height: self.size.height + insets.top * self.scale + insets.bottom * self.scale)

        UIGraphicsBeginImageContextWithOptions(cgSize, false, self.scale)
        defer { UIGraphicsEndImageContext() }

        let origin = CGPoint(x: insets.left * self.scale, y: insets.top * self.scale)
        self.draw(at: origin)

        return UIGraphicsGetImageFromCurrentImageContext()?.withRenderingMode(self.renderingMode)
    }
}

Usage example:

let margin:CGFloat = 16
self.imageView.image = image?.withInset(UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin))

Source

Hypersensitive answered 27/8, 2020 at 3:14 Comment(2)
All the answers here and this was the only one that worked. Thanks.Melodrama
this work, but removing * self.scale is betterExcoriation
W
10

One option is to use withAlignmentRectInsets, but it doesn't work with the layer border.

Another way is to use resizableImage(withCapInsets: resizingMode: .stretch) where you'd want to use positive inset values for smaller images.

Sample code:

private func setupQRImageView() -> UIImageView {
    let imageView = UIImageView()
    imageView.contentMode = .scaleAspectFit
    imageView.layer.borderColor = Default.imageBorderColor.cgColor
    imageView.layer.borderWidth = 4.0
    imageView.layer.cornerRadius = 6.0
    let imageInset: CGFloat = 8.0
    imageView.image = UIImage(named: "QR")?.resizableImage(withCapInsets: UIEdgeInsets(top: imageInset, left: imageInset, bottom: imageInset, right: imageInset), resizingMode: .stretch)
    return imageView
}

Produces the following result:

UIImageView with a border and padded inset

Withers answered 3/7, 2019 at 10:9 Comment(0)
I
5

You can add a UIView first and then you add your UIImageView inside the UIView with a padding of whatever you like, and if you want your gesture to get affected only in UIImageView, make it UserInteractionEnable to yes or if you want the gesture to be in the whole then you can add the gesture to the whole UIView

Intisar answered 31/8, 2015 at 5:44 Comment(0)
F
4

Try work around with UIImage within UIView like this ;

enter image description here

Fleer answered 13/4, 2019 at 18:39 Comment(3)
Please elaborate.Natator
Draw the UIImage inside an UIView and use autolayout to constrain UIImage to size you wantFleer
Thanks for this. The usual solutions were just causing loads of problems, this works as desired.Basil

© 2022 - 2024 — McMap. All rights reserved.