iOS Swift Rectangle - ios

I am trying to add a rectangular shape (curve as shown in picture) to my existing UIView.
.
This is the code I have implemented:
func drawRect(rect: CGRect) {
let y:CGFloat = 20
let curveTo:CGFloat = 0
let myBezier = UIBezierPath()
myBezier.move(to: CGPoint(x: 0, y: y))
myBezier.addQuadCurve(to: CGPoint(x: rect.width, y: y), controlPoint: CGPoint(x: rect.width / 2, y: curveTo))
myBezier.addLine(to: CGPoint(x: rect.width, y: rect.height))
myBezier.addLine(to: CGPoint(x: 0, y: rect.height))
myBezier.close()
let context = UIGraphicsGetCurrentContext()
context!.setLineWidth(4.0)
UIColor.yellow.setFill()
myBezier.fill()
}
Just to try and get a rectangle path to appear, however, when I open it in the simulator there is nothing. I believe it is because my other elements are overlayed on top of it is this correct? My full code is here
Thanks for your help.

Looking at your code. The UIViewController don't have overridden message drawRect. You should create custom class derived from UIView and override message drawRect there.

This could be made much more flexible, but it might suit your needs. If it doesn't, it could be a good starting point for you to get to what you want.
If you haven't looked at custom components / subclassing UIView / using IBInspectable and IBDesignable, this probably won't make much sense, so you might have some reading to do :)
//
// RoundedBottomImageView.swift
// SW3IBDesign
//
// Created by Don Mag on 2/27/17.
// Copyright © 2017 DonMag. All rights reserved.
//
import UIKit
#IBDesignable
class RoundedBottomImageView: UIView {
var imageView: UIImageView!
#IBInspectable var image: UIImage? {
didSet { self.imageView.image = image }
}
#IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
doMyInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
doMyInit()
}
func doMyInit() {
imageView = UIImageView()
imageView.backgroundColor = UIColor.red
imageView.contentMode = UIViewContentMode.scaleToFill
addSubview(imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = self.bounds
let rect = self.bounds
let y:CGFloat = rect.size.height - roundingValue
let curveTo:CGFloat = rect.size.height
let myBezier = UIBezierPath()
myBezier.move(to: CGPoint(x: 0, y: y))
myBezier.addQuadCurve(to: CGPoint(x: rect.width, y: y), controlPoint: CGPoint(x: rect.width / 2, y: curveTo))
myBezier.addLine(to: CGPoint(x: rect.width, y: 0))
myBezier.addLine(to: CGPoint(x: 0, y: 0))
myBezier.close()
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}
Example app: https://github.com/DonMag/IBDesignInspect
Edit: Example now includes buttons to demonstrate changing the image via code.
Edit2: Example app now has an Alternate Storyboard to show how the image can be "path clipped" without using a custom subclass.

Related

How to draw a curve like this in UIBezierPath Swift?

I am trying to develop a screen whose background looks like this:
Here I am trying to develop the gray curved background and it fills the lower part of the screen as well. I'm very new to UIBezierPath and I've tried this:
class CurvedView: UIView {
//MARK:- Data Types
//MARK:- View Setup
override func draw(_ rect: CGRect) {
let fillColor: UIColor = .blue
let path = UIBezierPath()
let y:CGFloat = 0
print(rect.height)
print(rect.width)
path.move(to: CGPoint(x: .zero, y: 100))
path.addLine(to: CGPoint(x: 60, y: 100))
path.addCurve(to: .init(x: 100, y: 0), controlPoint1: .init(x: 125, y: 80), controlPoint2: .init(x: 50, y: 80))
path.close()
fillColor.setFill()
path.fill()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .init(hex: "#dfe1e3")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.backgroundColor = .init(hex: "#dfe1e3")
}
}
This code gave me this:
I followed a lot of tutorials but I didn't get the exact understanding. I understood that for this curve I have to move to (0,100) and then add a line and then add a curve and ten extend the line add a curve then straight line lower curve and then straight line and close. But, when I started as you can see the blue line didn't cover the upper part. Can any one please help me?
Here some example that I create, you can change the value to make it more similar to what you want
Here a guide how control point in a curve work
Note: I called this code in viewDidload
let path = UIBezierPath()
let fillColor = UIColor.blue
let y: CGFloat = UIScreen.main.bounds.size.height
let x: CGFloat = UIScreen.main.bounds.size.width
let height: CGFloat = 200
path.move(to: CGPoint(x: 0, y: y)) // bottom left
path.addLine(to: CGPoint(x: 0, y: y - 20)) // top left
path.addCurve(to: CGPoint(x: x, y: y - height), controlPoint1: CGPoint(x: x * 2 / 3, y: y), controlPoint2: CGPoint(x: x * 5 / 6, y: y - height * 6 / 5)) // curve to top right
path.addLine(to: CGPoint(x: x, y: y)) // bottom right
path.close() // close the path from bottom right to bottom left
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = fillColor.cgColor
view.layer.addSublayer(shapeLayer)
in reference to #aiwiguna
class CurvedView: UIView {
//MARK:- Data Types
//MARK:- View Setup
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
let fillColor = UIColor.blue
let y: CGFloat = UIScreen.main.bounds.size.height
let x: CGFloat = UIScreen.main.bounds.size.width
let height: CGFloat = 200
path.move(to: CGPoint(x: 0, y: y)) // bottom left
path.addLine(to: CGPoint(x: 0, y: y - 20)) // top left
path.addCurve(to: CGPoint(x: x, y: y - height), controlPoint1: CGPoint(x: x * 2 / 3, y: y), controlPoint2: CGPoint(x: x * 5 / 6, y: y - height * 6 / 5)) // curve to top right
path.addLine(to: CGPoint(x: x, y: y)) // bottom right
path.close() // close the path from bottom right to bottom left
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = fillColor.cgColor
path.close()
fillColor.setFill()
path.fill()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.backgroundColor = .yellow
}
}

Trim UIView with 2 arcs

I have a UIView and I want to trim it with two circles, like I've drawn(sorry for the quality).
My code:
final class TrimmedView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let size = CGSize(width: 70, height: 70)
let innerRadius: CGFloat = 366.53658283002471
let innerBottomRadius: CGFloat = 297.88543112651564
let path = UIBezierPath()
path.move(to: CGPoint(x: -innerRadius + (size.width / 2), y: innerRadius))
path.addArc(withCenter: CGPoint(x: size.width / 2, y: innerRadius), radius: innerRadius, startAngle: CGFloat.pi, endAngle: 0, clockwise: true)
path.move(to: CGPoint(x: -innerBottomRadius + (size.width / 2), y: innerBottomRadius))
path.addArc(withCenter: CGPoint(x: size.width / 2, y: innerBottomRadius), radius: innerBottomRadius, startAngle: 0, endAngle: CGFloat.pi, clockwise: true)
path.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.shadowPath = path.cgPath
layer.mask = shapeLayer
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
ViewController:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let view = UIView(frame: CGRect(origin: CGPoint(x: (self.view.bounds.width - 70) / 2, y: (self.view.bounds.height - 70) / 2), size: CGSize(width: 70, height: 70)))
view.backgroundColor = .red
self.view.addSubview(view)
let view1 = TrimmedView(frame: view.frame)
view1.backgroundColor = .yellow
self.view.addSubview(view1)
}
I got this result. It seems for me that top trimming works but the bottom doesn't and I don't know why. Any help would be appreciated. Thanks.
Here is a custom view that should give you what you want.
The UIBezierPath uses QuadCurves for the top "convex" arc and the bottom "concave" arc.
It is marked #IBDesignable so you can see it at design-time in IB / Storyboard. The "height" of the arc and the fill color are each set as #IBInspectable so you can adjust those values at design-time as well.
To use it in Storyboard:
Add a normal UIView
change the Class to BohdanShapeView
in the Attributes Inspector pane, set the Arc Offset and the Fill Color
set the background color as with a normal view (you'll probably use clear)
Result:
To use it via code:
let view1 = BohdanShapeView(frame: view.frame)
view1.fillColor = .systemTeal
view1.arcOffset = 10
self.view.addSubview(view1)
Here is the class:
#IBDesignable
class BohdanShapeView: UIView {
#IBInspectable var arcOffset: CGFloat = 0.0
#IBInspectable var fillColor: UIColor = UIColor.white
let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
// add the shape layer
layer.addSublayer(shapeLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
// fill color for the shape
shapeLayer.fillColor = self.fillColor.cgColor
let width = bounds.size.width
let height = bounds.size.height
let bezierPath = UIBezierPath()
// start at arcOffset below top-left
bezierPath.move(to: CGPoint(x: 0.0, y: 0.0 + arcOffset))
// add curve to arcOffset below top-right
bezierPath.addQuadCurve(to: CGPoint(x: width, y: 0.0 + arcOffset), controlPoint: CGPoint(x: width * 0.5, y: 0.0 - arcOffset))
// add line to bottom-right
bezierPath.addLine(to: CGPoint(x: width, y: height))
// add curve to bottom-left
bezierPath.addQuadCurve(to: CGPoint(x: 0.0, y: height), controlPoint: CGPoint(x: width * 0.5, y: height - arcOffset * 2.0))
// close the path
bezierPath.close()
shapeLayer.path = bezierPath.cgPath
}
}

Suggestions regarding UIImageView customization

I'm trying to figure out the best way to recreate this image in code. I've thought about taking two UIImageViews and connecting them via constraints but that would only get me 50% of the way there because there wouldn't be a diagonal white line splitting the two unique colors. I also want to be able to programmatically change the color of each half of the UIImageView.
My class was very similar to what "May Rest in Peace" posted, but since I had put it together already, I'll go ahead and post it.
The main difference is that I implemented #IBDesignable and #IBInspectable so you can see it and make adjustments in Storyboard / IB
#IBDesignable
class AaronView: UIView {
let leftLayer: CAShapeLayer = CAShapeLayer()
let rightLayer: CAShapeLayer = CAShapeLayer()
let maskLayer: CAShapeLayer = CAShapeLayer()
#IBInspectable
var leftColor: UIColor = UIColor(red: 0.5, green: 0.6, blue: 0.8, alpha: 1.0) {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var rightColor: UIColor = UIColor(red: 0.0, green: 0.5, blue: 0.4, alpha: 1.0) {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var divColor: UIColor = UIColor.white {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var divAngle: CGFloat = 5.0 {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var divWidth: CGFloat = 8.0 {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var radius: CGFloat = 32.0 {
didSet {
setNeedsLayout()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
layer.addSublayer(leftLayer)
layer.addSublayer(rightLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
let x1 = bounds.minX
let y1 = bounds.minY
let x2 = bounds.maxX
let y2 = bounds.maxY
var path = UIBezierPath()
let offset = (bounds.width / 2) * tan(divAngle * CGFloat.pi / 180)
path.move(to: CGPoint(x: x1, y: y1))
path.addLine(to: CGPoint(x: x2 / 2.0 - divWidth / 2.0 + offset, y: y1))
path.addLine(to: CGPoint(x: x2 / 2.0 - divWidth / 2.0 - offset, y: y2))
path.addLine(to: CGPoint(x: x1, y: y2))
path.close()
leftLayer.path = path.cgPath
path = UIBezierPath()
path.move(to: CGPoint(x: x2 / 2.0 + divWidth / 2.0 + offset, y: y1))
path.addLine(to: CGPoint(x: x2, y: y1))
path.addLine(to: CGPoint(x: x2, y: y2))
path.addLine(to: CGPoint(x: x2 / 2.0 + divWidth / 2.0 - offset, y: y2))
path.close()
rightLayer.path = path.cgPath
leftLayer.fillColor = leftColor.cgColor
rightLayer.fillColor = rightColor.cgColor
maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
layer.mask = maskLayer
backgroundColor = divColor
}
}
Using Defaults:
Result:
and some changes:
Result:
A UIImageView holds a static bitmap image. You could just generate an image like that, save it as a JPEG/PNG/TIF, and load the image into a UIImageView as a bitmap. That doesn't sound like what you want however.
I'd suggest creating a custom subclass of UIView. From there you could go a couple of different ways.
You could have your view override the draw() method for UIView and use Core Graphics calls to draw into the graphics context. Core Graphics is pretty specialized and will require some research to get the hang of.
You could have your custom view add Core Animation (CA) layers that draw your shapes for you. The class CAShapeLayer would be a good choice for this. You'll need to read up on CALayers and how to use them (which is also fairly arcane bit of learning.)
In general Apple steers you towards using layers and letting the system do the rendering for you. That's probably how I would do this. (Using CAShapeLayers, which in turn use CGPath objects.)
I created a custom view based on what you need based on #DuncanC's suggestions
class AngledSplitView: UIView {
var leftLayer: CAShapeLayer!
var rightLayer: CAShapeLayer!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
init (frame: CGRect,
leftColor: UIColor,
rightColor: UIColor,
separatorWidth: CGFloat,
separatorAngleInDegrees: CGFloat) {
super.init(frame: frame)
setupViews(leftColor: leftColor,
rightColor: rightColor,
separatorWidth: separatorWidth,
separatorAngleInDegrees: separatorAngleInDegrees)
}
func setupViews(leftColor: UIColor,
rightColor: UIColor,
separatorWidth: CGFloat,
separatorAngleInDegrees: CGFloat) {
// sets the image's frame to fill our view
createLeftView(leftColor: leftColor, separatorWidth: separatorWidth, separatorAngleInDegrees: separatorAngleInDegrees)
createRightView(rightColor: rightColor, separatorWidth: separatorWidth, separatorAngleInDegrees: separatorAngleInDegrees)
}
func setLeftColor(leftColor: UIColor) {
leftLayer.fillColor = leftColor.cgColor
}
func setRightColor(rightColor: UIColor) {
rightLayer.fillColor = rightColor.cgColor
}
func createLeftView(leftColor: UIColor,
separatorWidth: CGFloat,
separatorAngleInDegrees: CGFloat) {
let path = UIBezierPath()
let leftLayer = CAShapeLayer()
let offset = (bounds.height / 2) * tan(separatorAngleInDegrees * CGFloat.pi / 180)
path.move(to: bounds.origin)
path.addLine(to: CGPoint(x: bounds.width / 2 - separatorWidth / 2 + offset,
y: bounds.origin.y))
path.addLine(to:CGPoint(x: bounds.width / 2 - separatorWidth / 2 - offset,
y: bounds.height))
path.addLine(to:CGPoint(x: bounds.origin.x, y: bounds.height))
path.addLine(to:bounds.origin)
path.close()
leftLayer.path = path.cgPath
leftLayer.fillColor = leftColor.cgColor
self.layer.addSublayer(leftLayer)
}
func createRightView(rightColor: UIColor,
separatorWidth: CGFloat,
separatorAngleInDegrees: CGFloat) {
let path = UIBezierPath()
let rightLayer = CAShapeLayer()
let offset = (bounds.height / 2) * tan(separatorAngleInDegrees * CGFloat.pi / 180)
path.move(to: CGPoint(x: bounds.width / 2 + separatorWidth / 2 + offset,
y: bounds.origin.y))
path.addLine(to: CGPoint(x: bounds.width / 2 + separatorWidth / 2 + offset,
y: bounds.origin.y))
path.addLine(to:CGPoint(x: bounds.width / 2 + separatorWidth / 2 - offset,
y: bounds.height))
path.addLine(to:CGPoint(x: bounds.width, y: bounds.height))
path.addLine(to:CGPoint(x: bounds.width, y: bounds.origin.y))
path.close()
rightLayer.path = path.cgPath
rightLayer.fillColor = rightColor.cgColor
self.layer.addSublayer(rightLayer)
}
}
You can use it like this:
let customView = AngledSplitView(
frame: CGRect(x: 20, y: 30, width: view.frame.width - 40, height:
view.frame.height / 4),
leftColor: .red,
rightColor: .blue,
separatorWidth: 20,
separatorAngleInDegrees: 45)
view.addSubview(customView)

How Do i create UIView like in the image?

i want to add curve in my UIView as shown in image.
How can i create such uiview?
You can use UIBezierPath and use addCurve method to create your view.
//1. Create this new Class
class ComplexView: UIView {
var path: UIBezierPath!
override init(frame: CGRect) {
super.init(frame: frame)
self.alpha = 0.3
complexShape()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
// Specify the fill color and apply it to the path.
UIColor.blue.setFill()
path.fill()
// Specify a border (stroke) color.
UIColor.magenta.setStroke()
path.stroke()
}
func complexShape() {
path = UIBezierPath()
path.move(to: CGPoint(x: 0.0, y: 0.0))
path.addCurve(to: CGPoint(x: 0, y: self.frame.size.height),
controlPoint1: CGPoint(x: 50.0, y: 25.0),
controlPoint2: CGPoint(x: 50.0, y: self.frame.size.height - 25.0))
path.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
self.backgroundColor = UIColor.orange
self.layer.mask = shapeLayer
}
}
In your ViewController call this View and add this view to your main view.
//2. In you Viewcontoller add ComplexView
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let width: CGFloat = 100.0
let height: CGFloat = 500.0
let complexView = ComplexView(frame: CGRect(x: 0,
y: self.view.frame.size.height/2 - height/2,
width: width,
height: height))
self.view.addSubview(complexView)
}
You need to play around addCurve method to get your desired shape.

Corner radius image Swift

I'm trying to make this corner radius image...it's not exactly the same shape of the image..any easy answer instead of trying random numbers of width and height ?
thanks alot
let rectShape = CAShapeLayer()
rectShape.bounds = self.mainImg.frame
rectShape.position = self.mainImg.center
rectShape.path = UIBezierPath(roundedRect: self.mainImg.bounds, byRoundingCorners: [.bottomLeft , .bottomRight ], cornerRadii: CGSize(width: 50, height: 4)).cgPath
You can use QuadCurve to get the design you want.
Here is a Swift #IBDesignable class that lets you specify the image and the "height" of the rounding in Storyboard / Interface Builder:
#IBDesignable
class RoundedBottomImageView: UIView {
var imageView: UIImageView!
#IBInspectable var image: UIImage? {
didSet { self.imageView.image = image }
}
#IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
doMyInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
doMyInit()
}
func doMyInit() {
imageView = UIImageView()
imageView.backgroundColor = UIColor.red
imageView.contentMode = UIViewContentMode.scaleAspectFill
addSubview(imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = self.bounds
let rect = self.bounds
let y:CGFloat = rect.size.height - roundingValue
let curveTo:CGFloat = rect.size.height + roundingValue
let myBezier = UIBezierPath()
myBezier.move(to: CGPoint(x: 0, y: y))
myBezier.addQuadCurve(to: CGPoint(x: rect.width, y: y), controlPoint: CGPoint(x: rect.width / 2, y: curveTo))
myBezier.addLine(to: CGPoint(x: rect.width, y: 0))
myBezier.addLine(to: CGPoint(x: 0, y: 0))
myBezier.close()
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}
Result with 300 x 200 image view, rounding set to 40:
Edit - (3.5 years later)...
To answer #MiteshDobareeya comment, we can switch the rounded edge from Bottom to Top by transforming the bezier path:
let c = CGAffineTransform(scaleX: 1, y: -1).concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
It's been quite a while since this answer was originally posted, so a few changes:
subclass UIImageView directly - no need to make it a UIView with an embedded UIImageView
add a Bool roundTop var
if set to False (the default), we round the Bottom
if set to True, we round the Top
re-order and "name" our path points for clarity
So, the basic principle:
We create a UIBezierPath and:
move to pt1
add a line to pt2
add a line to pt3
add a quad-curve to pt4 with controlPoint
close the path
use that path for a CAShapeLayer mask
the result:
If we want to round the Top, after closing the path we can apply apply a scale transform using -1 as the y value to vertically mirror it. Because that transform mirror it at "y-zero" we also apply a translate transform to move it back down into place.
That gives us:
Here's the updated class:
#IBDesignable
class RoundedTopBottomImageView: UIImageView {
#IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
#IBInspectable var roundTop: Bool = false {
didSet {
self.setNeedsLayout()
}
}
override func layoutSubviews() {
super.layoutSubviews()
let r = bounds
let myBezier = UIBezierPath()
let pt1: CGPoint = CGPoint(x: r.minX, y: r.minY)
let pt2: CGPoint = CGPoint(x: r.maxX, y: r.minY)
let pt3: CGPoint = CGPoint(x: r.maxX, y: r.maxY - roundingValue)
let pt4: CGPoint = CGPoint(x: r.minX, y: r.maxY - roundingValue)
let controlPoint: CGPoint = CGPoint(x: r.midX, y: r.maxY + roundingValue)
myBezier.move(to: pt1)
myBezier.addLine(to: pt2)
myBezier.addLine(to: pt3)
myBezier.addQuadCurve(to: pt4, controlPoint: controlPoint)
myBezier.close()
if roundTop {
// if we want to round the Top instead of the bottom,
// flip the path vertically
let c = CGAffineTransform(scaleX: 1, y: -1) //.concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
}
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}
You can try with UIView extension. as
extension UIView {
func setBottomCurve(){
let offset = CGFloat(self.frame.size.height + self.frame.size.height/1.8)
let bounds = self.bounds
let rectBounds = CGRect(x: bounds.origin.x,
y: bounds.origin.y ,
width: bounds.size.width,
height: bounds.size.height / 2)
let rectPath = UIBezierPath(rect: rectBounds)
let ovalBounds = CGRect(x: bounds.origin.x - offset / 2,
y: bounds.origin.y ,
width: bounds.size.width + offset,
height: bounds.size.height)
let ovalPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = rectPath.cgPath
self.layer.mask = maskLayer
}
}
& use it in viewWillAppear like methods where you can get actual frame of UIImageView.
Usage:
override func viewWillAppear(_ animated: Bool) {
//use it in viewWillAppear like methods where you can get actual frame of UIImageView
myImageView.setBottomCurve()
}

Resources