rendering

As the picture shows, there is a small arrow on the left side of the picture

The principle of

The principle is simple: take an image, MaskImgae, stretch it and then crop it to fit the outline

steps

Here pick the point to say, layout of what to do according to their own will. I fixed the display size of the image to 102 * 152

1. Stretch the MaskImgae

// Set the stretch range
let stretchInsets = UIEdgeInsetsMake(30.28.23.28)
// The image to be stretched
let stretchImage = UIImage(named: "SenderImageNodeMask")
// Stretch
let bubbleMaskImage = stretchImage.resizableImage(withCapInsets: stretchInsets, resizingMode: .stretch)
Copy the code

Stretching looks like this

2. Set clipping area for imageView

Here my imageView is called chatImgView. The stretched image above is temporarily assigned to chatImgView, just to show you the effect. Please remember to change it back if there is an assignment

All right, let’s crop it

// Create a new layer
let layer = CALayer(a)// Set the layer to display the stretched MaskImgae
layer.contents = bubbleMaskImage.cgImage
// Set the stretch range (note: here the CGRect of contentsCenter is proportional (not absolute))
layer.contentsCenter = self.CGRectCenterRectForResizableImage(bubbleMaskImage)
// Set the layer size to the same as chatImgView
layer.frame = CGRect(x: 0, y: 0, width: 102, height: 152)
// Set the scale
layer.contentsScale = UIScreen.main.scale
// Set the opacity
layer.opacity = 1
// Set the clipping range
self.chatImgView.layer.mask = layer
// Set clipping out the excess area
self.chatImgView.layer.masksToBounds = true
Copy the code
func CGRectCenterRectForResizableImage(_ image: UIImage) -> CGRect {
    // LXFLog("\(image.capInsets)")
    CapInsets UIEdgeInsetsMake(30, 28, 23, 28)
    return CGRect(
        x: image.capInsets.left / image.size.width,
        y: image.capInsets.top / image.size.height,
        width: (image.size.width - image.capInsets.right - image.capInsets.left) / image.size.width,
        height: (image.size.height - image.capInsets.bottom - image.capInsets.top) / image.size.height
    )
}
Copy the code

And you’re done

Explain a little bit

UIEdgeInsetsMake

MaskImgae is 56 by 50 in size

// UIEdgeInsetsMake(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat)
UIEdgeInsetsMake(30.28.23.28)
Copy the code

The red range is the range to be stretched.

contentsCenter

This is a full stretch of an area, default if not set

CGRect(x: 0, y: 0, width: 1, height: 1)
Copy the code

I’m just going to scale it so let’s see what happens if I don’t set the contentsCenter value

var contentsCenter: CGRect { get set }
Description	
The rectangle that defines how the layer contents are scaled
ifThe layer's contents are resized.Animatable.
Copy the code

If the contents of the layer are resized, then this rectangle is defined to tell the layer how the contents of the layer are resized

That’s clear. Our image is stretched and then drawn to the layer. In order to display our image correctly, we need to tell the layer how it was stretched. Yes, the scope specified by the code below

UIEdgeInsetsMake(30.28.23.28)
Copy the code

However, as mentioned above, the CGRect assigned by contentsCenter is proportional, not absolute, so now we have to get the proportional value through (30, 28, 23, 28). The conversion method is given above. Is CGRectCenterRectForResizableImage we to print the image. The capInsets content

LXFLog("\(image.capInsets)")
LXFLog("\(image.capInsets.top)")
LXFLog("\(image.capInsets.bottom)")
LXFLog("\(image.capInsets.left)")
LXFLog("\(image.capInsets.right)")
Copy the code

Print the result

UIEdgeInsets(Top: 30.0, left: 28.0, bottom: 23.0, Right: 28.0Copy the code

Good, now in combination with the code in the following figure and CGRectCenterRectForResizableImage proportion was very clear how to

Attached is related project: Swift 3.0 high imitation wechat