Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a custom shape to an UIImageView in Swift?

I'm trying to add a custom shape to an imageView. Please check the below images.

This is the required one:

Required Image Shape

This is what I have done so far:

Current Image Shape

I'm new to Core Graphics and I have done this so far:

    private func customImageClipper(imageV: UIImageView){

    let path = UIBezierPath()

    let size = imageV.frame.size

    print(size)

    path.move(to: CGPoint(x: 0.0, y: size.height))

    path.addLine(to: CGPoint(x: 0.8, y: size.height/2))

    path.close()

    let shape = CAShapeLayer()

    shape.path = path.cgPath

    imageV.layer.sublayers = [shape]

}

I'm creating a function to achieve a shape like this, but whenever I pass the imageView into this function, I can not see any change at all. I know that I have to move from points to another point to achieve this shape, but I have never done this. Any help would be appreciated. This is how I'm calling this function:

imageV.layoutIfNeeded()

customImageClipper(imageV: imageV)

P.S.: I'm not using Storyboard, I have created this programmatically.

like image 769
Rob13 Avatar asked Jan 11 '20 11:01

Rob13


2 Answers

There are many ways to create shapes using UIBezierPaths. This post here discusses the use of the draw function to create a shape.

Here is an example using your clip function within the cell.

func clip(imageView: UIView, withOffset offset: CGFloat) {
    let path = UIBezierPath()

    //Move to Top Left
    path.move(to: .init(x: imageView.bounds.size.width * offset, y: 0))

    //Draw line from Top Left to Top Right
    path.addLine(to: .init(x: imageView.bounds.size.width, y: 0))

    //Draw Line from Top Right to Bottom Right
    path.addLine(to: .init(x: imageView.bounds.size.width * (1 - offset), y: imageView.bounds.size.height))

    //Draw Line from Bottom Right to Bottom Left
    path.addLine(to: .init(x: 0, y: imageView.bounds.size.height))

    //Close Path
    path.close()

    //Create the Shape Mask for the ImageView
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.fillColor = UIColor.black.cgColor
    imageView.layer.mask = shapeLayer
}

In this function, the offset is the amount of angle you would like on the shape, ranging from 0 to 1. (0.4) seems to work for your requirements.

This shares a lot of similarities with Apseri's answer, except I chose the route of percentages, rather than exact size. Nothing wrong with either approach, I just found it easier to understand with percentages. :)

One last note to point out, I used this function in the layoutSubviews function.

override func layoutSubviews() {
    super.layoutSubviews()
    imageView.layoutIfNeeded()
    clip(imageView: self.imageView, withOffset: 0.4)
}

This output the following image:

Image of a cell showing custom shape

Hope this helps.

like image 131
Paulo Avatar answered Sep 22 '22 18:09

Paulo


Here is example of some path clipping. Of course path can be also put via parameters, and this can be applied to any view, as shown.

Before:

enter image description here

After (grey background is below ScrollView background):

enter image description here

func customImageClipper(imageV: UIView){

    let path = UIBezierPath()
    let size = imageV.frame.size

    path.move(to: CGPoint(x: size.width/3.0, y: 0))
    path.addLine(to: CGPoint(x: size.width/3.0 + 50, y: 0))
    path.addLine(to: CGPoint(x: size.width/3.0, y: size.height))
    path.addLine(to: CGPoint(x: size.width/3.0 - 50, y: size.height))
    path.addLine(to: CGPoint(x: size.width/3.0, y: 0))
    path.close()

    let shape = CAShapeLayer()
    shape.path = path.cgPath
    shape.fillColor = UIColor.black.cgColor

    imageV.layer.mask = shape
}
like image 44
Asperi Avatar answered Sep 22 '22 18:09

Asperi