Set stretching parameters for images programmatically in swift for iOS

后端 未结 1 1483
没有蜡笔的小新
没有蜡笔的小新 2021-02-09 07:57

So if we want to stretch only parts of an image, be it a regular image or a background image, we use the following settings in layout editor:

How do you set tho

相关标签:
1条回答
  • 2021-02-09 08:15

    Specifying the cap insets of your image

    You can set the stretch specifics by making use of the UIImage method .resizableImageWithCapInsets(_:UIEdgeInsets, resizingMode: UIImageResizingMode).

    Declaration

    func resizableImageWithCapInsets(capInsets: UIEdgeInsets, resizingMode: UIImageResizingMode) -> UIImage
    

    Description

    Creates and returns a new image object with the specified cap insets and options.

    A new image object with the specified cap insets and resizing mode.

    Parameters

    capInsets: The values to use for the cap insets.

    resizingMode: The mode with which the interior of the image is resized.


    Example: custom stretching using the specified cap insets

    As an example, let's try to---programmatically---stretch my (current) profile picture along its width, precisely at my right leg (left side from viewing point of view), and leave the rest of the image with its original proportions. This could be comparable to stretching the width of some button texture to the size of its content.

    First, let's load our original image foo.png as an UIImage object:

    let foo = UIImage(named: "foo.png") // 328 x 328
    

    Now, using .resizableImageWithCapInsets(_:UIEdgeInsets, resizingMode: UIImageResizingMode), we'll define another UIImage instance, with specified cap insets (to the middle of my right leg), and set resizing mode to .Stretch:

    /* middle of right leg at ~ |-> 0.48: LEG :0.52 <-| along 
       image width (for width normalized to 1.0)                */
    let fooWidth = foo?.size.width ?? 0
    let leftCapInset = 0.48*fooWidth
    let rightCapInset = fooWidth-leftCapInset // = 0.52*fooWidth
    
    let bar = UIEdgeInsets(top: 0, left: leftCapInset, bottom: 0, right: rightCapInset)
    let fooWithInsets = foo?.resizableImageWithCapInsets(bar, resizingMode: .Stretch) ?? UIImage()
    

    Note that 0.48 literal above corresponds to the value you enter for X in the interface builder, as shown in the image in your question above (or as described in detail in the link provided by matt).

    Moving on, we finally place the image with cap insets in an UIImageView, and let the width of this image view be larger than the width of the image

    /* put 'fooWithInsets' in an imageView.
       as per default, frame will cover 'foo.png' size */
    let imageView = UIImageView(image: fooWithInsets)
    
    /* expand frame width, 328 -> 600 */
    imageView.frame = CGRect(x: 0, y: 0, width: 600, height: 328)
    

    The resulting view stretches the original image as specified, yielding an unproportionally long leg.

    Now, as long as the frame of the image has 1:1 width:height proportions (328:328), stretching will be uniform, as if only fitting any image to a smaller/larger frame. For any frame with width values larger than the height (a:1, ratio, a>1), the leg will begin to stretch unproportionally.


    Extension to match the X, width, Y and height stretching properties in the Interface Builder

    Finally, to thoroughly actually answer your question (which we've really only done implicitly above), we can make use of the detailed explanation of the X, width, Y and height Interface Builder stretching properties in the link provided by matt, to construct our own UIImage extension using (apparently) the same properties, translated to cap insets in the extension:

    extension UIImage {
        func resizableImageWithStretchingProperties(
        X X: CGFloat, width widthProportion: CGFloat,
        Y: CGFloat, height heightProportion: CGFloat) -> UIImage {
    
            let selfWidth = self.size.width
            let selfHeight = self.size.height
    
            // insets along width
            let leftCapInset = X*selfWidth*(1-widthProportion)
            let rightCapInset = (1-X)*selfWidth*(1-widthProportion)
    
            // insets along height
            let topCapInset = Y*selfHeight*(1-heightProportion)
            let bottomCapInset = (1-Y)*selfHeight*(1-heightProportion)
    
            return self.resizableImageWithCapInsets(
                UIEdgeInsets(top: topCapInset, left: leftCapInset,
                    bottom: bottomCapInset, right: rightCapInset),
                resizingMode: .Stretch)
        }
    }
    

    Using this extension, we can achieve the same horizontal stretching of foo.png as above, as follows:

    let foo = UIImage(named: "foo.png") // 328 x 328
    let fooWithInsets = foo?.resizableImageWithStretchingProperties(
        X: 0.48, width: 0, Y: 0, height: 0) ?? UIImage()
    
    let imageView = UIImageView(image: fooWithInsets)
    imageView.frame = CGRect(x: 0, y: 0, width: 600, height: 328)
    

    Extending our example: stretching width as well as height

    Now, say we want to stretch my right leg as above (along width), but in addition also my hands and left leg along the height of the image. We control this by using the Y property in the extension above:

    let foo = UIImage(named: "foo.png") // 328 x 328
    let fooWithInsets = foo?.resizableImageWithStretchingProperties(
        X: 0.48, width: 0, Y: 0.45, height: 0) ?? UIImage()
    
    let imageView = UIImageView(image: fooWithInsets)
    imageView.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
    

    Yielding the following stretched image:


    The extension obviously allows for a more versatile use of the cap inset stretching (comparable versatility as using the Interface Builder), but note that the extension, in its current form, does not include any user input validation, so it's up to the caller to use arguments in the correct ranges.

    Finally, a relevant note for any operations covering images and their coordinates:

    Note: Image coordinate axes x (width) and y (height) run as

    x (width):  left to right (as expected)
    y (height): top to bottom (don't miss this!)
    
    0 讨论(0)
提交回复
热议问题