How to make - Hybrid cornerRadius - Swift 5 - ios

I hope all are doing well.
Here's the following, I need to make the cornerRadius like the one in the example, but in the icon, he doesn't change at all and in a Carousel, he only makes the bottom corners, not the top ones.
What can I do accomplish this? My corners don't have the same radius on all sides.
Icon Corners Example
I have a function for the cornerRadius:
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
In my icon I make the call this way:
bigIconContentView.roundCorners([.topRight, .bottomLeft], radius: 30)
bigIconContentView.roundCorners([.topLeft], radius: 10)
And in my Carousel I'm calling this way:
bStoreImage.roundCorners([.topLeft, .topRight], radius: 20)
beaconsContentView.roundCorners([.topLeft, .topRight], radius: 20)
beaconsContentView.roundCorners([.bottomLeft, .bottomRight], radius: 7)
What I'm doing wrong? What can I do to make them work and make these sides with different Radius?
I can make two roundCorners call to the same element but with different attributes? Like I did in my examples?
Thanks for your help!

Let's focus on roundCorners(_ corners: radius:)
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let someNewMask = somethingNew(corners, radius: radius)
self.layer.mask = someNewMask
}
You are doing:
bigIconContentView.roundCorners([.topRight, .bottomLeft], radius: 30)
bigIconContentView.roundCorners([.topLeft], radius: 10)
Which in the ends, is doing this:
let someNewMask1 = somethingNew([.topRight, .bottomLeft], radius: 30)
bigIconContentView.mask = someNewMask1
let someNewMask2 = somethingNew([. topLeft], radius: 10)
bigIconContentView.mask = someNewMask2
So you are doing:
bigIconContentView.mask = someNewMask1
bigIconContentView.mask = someNewMask2
You see the issue? You are overriding bigIconContentView mask with a new one each time (the last one called).
You have to apply the different corners all together (there is nothing complicated in corner radius)
extension UIView {
func roundCornersRadii(topLeft: CGFloat = 0, topRight: CGFloat = 0, bottomLeft: CGFloat = 0, bottomRight: CGFloat = 0) {
let path = UIBezierPath()
path.move(to: CGPoint(x: topLeft, y: 0))
path.addLine(to: CGPoint(x: bounds.width - topRight, y: 0))
path.addArc(withCenter: CGPoint(x: bounds.width - topRight, y: topRight),
radius: topRight,
startAngle: -CGFloat.pi/2.0,
endAngle: 0,
clockwise: true)
path.addLine(to: CGPoint(x: bounds.width, y: bounds.width - bottomRight))
path.addArc(withCenter: CGPoint(x: bounds.width - bottomRight, y: bounds.height - bottomRight),
radius: bottomRight,
startAngle: 0,
endAngle: CGFloat.pi/2.0,
clockwise: true)
path.addLine(to: CGPoint(x: bottomRight, y: bounds.height))
path.addArc(withCenter: CGPoint(x: bottomLeft, y: bounds.height - bottomLeft),
radius: bottomLeft,
startAngle: CGFloat.pi/2.0,
endAngle: CGFloat.pi,
clockwise: true)
path.addLine(to: CGPoint(x: 0, y: topLeft))
path.addArc(withCenter: CGPoint(x: topLeft, y: topLeft),
radius: topLeft,
startAngle: CGFloat.pi,
endAngle: CGFloat.pi/2.0,
clockwise: true)
path.close()
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
Adding sample test:
let superView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
let subview = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
superView.backgroundColor = .red
subview.backgroundColor = .blue
subview.roundCornersRadii(topLeft: 20, topRight: 30, bottomLeft: 40, bottomRight: 50)
superView.addSubview(subview)
or in your case:
let superView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
let subview = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
superView.backgroundColor = .red
subview.backgroundColor = .blue
subview.roundCornersRadii(topLeft: 20, topRight: 30, bottomLeft: 40, bottomRight: 50)
subview.roundCornersRadii(topLeft: 10, topRight: 30, bottomLeft: 30)
superView.addSubview(subview)

Related

Shape in ios swift

how to draw the curve with blur background?
here I have attached my code but am not getting the exact output
#IBDesignable class CurvedHeaderView: UIView {
#IBInspectable var curveHeight:CGFloat = 50.0
var curvedLayer = CAShapeLayer()
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.move(to: CGPoint(x: 0, y: rect.height))
// path.addLine(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: rect.width, y: rect.height))
path.addArc(withCenter: CGPoint(x: CGFloat(rect.width) - curveHeight, y: 100), radius: curveHeight, startAngle: 0, endAngle: 1.5 * CGFloat.pi, clockwise: false)
// path.addArc(withCenter: CGPoint(x: CGFloat(rect.width) - curveHeight, y: rect.height), radius: curveHeight, startAngle: 0, endAngle: 1.5 * CGFloat.pi, clockwise: false)
// path.addLine(to: CGPoint(x: curveHeight, y: rect.height - curveHeight))
// path.addLine(to: CGPoint(x: curveHeight, y: 50))
path.addLine(to: CGPoint(x: curveHeight, y: curveHeight))
path.addArc(withCenter: CGPoint(x: curveHeight, y: 0), radius: curveHeight, startAngle: 0, endAngle: CGFloat.pi, clockwise: true)
path.addLine(to: CGPoint(x: 0, y: 0))
// path.addArc(withCenter: CGPoint(x: curveHeight, y: rect.height - (curveHeight * 2.0)), radius: curveHeight, startAngle: 0, endAngle: CGFloat.pi, clockwise: true)
path.close()
curvedLayer.path = path.cgPath
curvedLayer.fillColor = UIColor.white.cgColor
curvedLayer.frame = rect
self.layer.insertSublayer(curvedLayer, at: 0)
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowRadius = 10.0
self.layer.shadowOpacity = 0.7
}
}
Please share me reference if anything wrong
Thanks in advance
I have tried but it showing code working but not exactly been getting
#IBOutlet weak var blurEffectView: UIVisualEffectView!
override func viewDidLayoutSubviews() {
let maskView = CurvedHeaderView(frame: blurEffectView.bounds)
maskView.clipsToBounds = true;
maskView.backgroundColor = UIColor.clear
blurEffectView.mask = maskView
}

How to add Curve left and right side in UIView for swift

I tried to add a curve but not working.
I have attached the image left side is given by the designer, the right side I have done in swift.
here the if I add corner radius not working for the curve if add curve corner radius not working.
I have added left side and right side separate views, how it's possible to achieve the remove the super view background-color and curve.
extension UIView {
func roundCorners(
corners: UIRectCorner,
radius: CGFloat
) {
let path = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(
width: radius,
height: radius
)
)
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
// here I am using on UITableviewCell in layoutSubview
leftCurve.roundCorners(corners: [.topRight,.bottomRight], radius: 20)
rightCurver.roundCorners(corners: [.topLeft,.bottomLeft], radius: 20)
Here is a demo for add curve to both side using UIBezierPath
class ShapeView: UIView {
var path: UIBezierPath = UIBezierPath()
// Set you circle position for verticle.
var circleYPosition: CGFloat = 50 {
didSet {
self.setNeedsDisplay()
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor.clear
// Here apply shadow
}
override func draw(_ rect: CGRect) {
super.draw(rect)
// 4 corners radious
UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 10, height: 10)).addClip()
// Left - right circle
path.move(to: CGPoint(x: 0, y: self.frame.size.height))
//left side
path.addArc(withCenter: CGPoint(x: 0, y: self.circleYPosition - 15),
radius: 10,
startAngle: CGFloat((90 * Double.pi) / 180),
endAngle: CGFloat((270 * Double.pi) / 180),
clockwise: false)
path.addLine(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: self.frame.size.width, y: 0))
path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
path.move(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
//right side
path.addArc(withCenter: CGPoint(x: self.frame.size.width, y: self.circleYPosition - 15),
radius: 10,
startAngle: CGFloat((270 * Double.pi) / 180),
endAngle: CGFloat((90 * Double.pi) / 180),
clockwise: false)
path.close()
UIColor.white.setFill()
path.fill()
// Center Dash path
let dashPath = UIBezierPath()
dashPath.move(to: CGPoint(x: self.bounds.minX + 12, y: self.circleYPosition - 15))
dashPath.addLine(to: CGPoint(x: self.bounds.maxX - 12, y: self.circleYPosition - 15))
dashPath.setLineDash([5,5], count: 2, phase: 0.0)
dashPath.lineWidth = 1.0
dashPath.lineCapStyle = .butt
UIColor.lightGray.set()
dashPath.stroke()
}
}

Redraw CoreGraphics drawing when device orientation changed

I working on app where I want to make custom shape button like this below
for this I'm using coregraphics to draw that shape for button and here code of button
class RewardStepsButton: UIButton {
#IBInspectable var firstStep: Bool = true{
didSet{
if firstStep{
secondStep = false
thirdStep = false
}
}
}
#IBInspectable var secondStep: Bool = false{
didSet{
if secondStep{
firstStep = false
thirdStep = false
}
}
}
#IBInspectable var thirdStep: Bool = false{
didSet{
if thirdStep{
firstStep = false
secondStep = false
}
}
}
#IBInspectable var buttonColor: UIColor = UIColor.lightGray
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
let path = UIBezierPath()
let btnLayer = CAShapeLayer()
if firstStep{
path.addArc(withCenter: CGPoint(x: 5, y: 5), radius: 5, startAngle: .pi, endAngle: 3 * .pi / 2, clockwise: true)
path.addLine(to: CGPoint(x: self.bounds.width - 15, y: 0))
path.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height / 2))
path.addLine(to: CGPoint(x: self.bounds.width - 15, y: self.bounds.height))
path.addArc(withCenter: CGPoint(x: 5, y: self.bounds.height - 5), radius: 5, startAngle: .pi / 2, endAngle: .pi, clockwise: true)
path.close()
}else if secondStep{
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: self.bounds.width - 15, y: 0))
path.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height / 2))
path.addLine(to: CGPoint(x: self.bounds.width - 15, y: self.bounds.height))
path.addLine(to: CGPoint(x: 0, y: self.bounds.height))
path.addLine(to: CGPoint(x: 15, y: self.bounds.height / 2))
path.addLine(to: CGPoint(x: 0, y: 0))
}else{
path.move(to: CGPoint(x: 0, y: 0))
path.addArc(withCenter: CGPoint(x: self.bounds.width - 5, y: 5), radius: 5, startAngle: 3 * .pi / 2, endAngle: 2 * .pi, clockwise: true)
path.addArc(withCenter: CGPoint(x: self.bounds.width - 5, y: self.bounds.height - 5), radius: 5, startAngle: 2 * .pi, endAngle:.pi / 2, clockwise: true)
path.addLine(to: CGPoint(x: 0, y: self.bounds.height))
path.addLine(to: CGPoint(x: 15, y: self.bounds.height / 2))
path.close()
}
btnLayer.path = path.cgPath
btnLayer.fillColor = self.buttonColor.cgColor
self.layer.addSublayer(btnLayer)
self.bringSubviewToFront(self.titleLabel!)
if thirdStep || secondStep{
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 25, bottom: 0, right: 0)
}else{
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
}
}
}
now it works almost perfect when I run the application buttons draw on app same as I want see below
now the problem it that when I changed the orientation of device, shape of drawing button is same doesn't refresh.
so I googled it and try to find solution and lot of answer were use
setNeedsDisplay() method for this so I use that method also but problem is, it draw another shape or add another layer and not erase the previous one. see this
When app load
when landscape orientation
when again portrait
please give me solution or idea how to solve this mess, Thanks.
Dont add layer in draw() method as in calls every time you call setNeedsLayout or layoutifNeeded ... use to add them in common init()
self.layer.addSublayer(btnLayer)
remove this line from draw() method
//MARK:- initializers
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
private func commonInit(){
self.layer.addSublayer(btnLayer)
}

All four corner of a view having different radius

How do i design a UIView whose all 4 corners have different corner radius. So, UIView with its top right corner radius of 20, top left corner radius of 30, bottom left corner radius of 10 and bottom right corner radius of 20
I want to add different cornerRadius to Viw Container shown in image.
using UIBEZIER method cuts off the share comment and like portion.
viw Container is pinned to cell
You can use this UIView extension. It will create and apply a mask layer according to your radius values.
extension UIView {
func applyRadiusMaskFor(topLeft: CGFloat = 0, bottomLeft: CGFloat = 0, bottomRight: CGFloat = 0, topRight: CGFloat = 0) {
let path = UIBezierPath()
path.move(to: CGPoint(x: bounds.width - topRight, y: 0))
path.addLine(to: CGPoint(x: topLeft, y: 0))
path.addQuadCurve(to: CGPoint(x: 0, y: topLeft), controlPoint: .zero)
path.addLine(to: CGPoint(x: 0, y: bounds.height - bottomLeft))
path.addQuadCurve(to: CGPoint(x: bottomLeft, y: bounds.height), controlPoint: CGPoint(x: 0, y: bounds.height))
path.addLine(to: CGPoint(x: bounds.width - bottomRight, y: bounds.height))
path.addQuadCurve(to: CGPoint(x: bounds.width, y: bounds.height - bottomRight), controlPoint: CGPoint(x: bounds.width, y: bounds.height))
path.addLine(to: CGPoint(x: bounds.width, y: topRight))
path.addQuadCurve(to: CGPoint(x: bounds.width - topRight, y: 0), controlPoint: CGPoint(x: bounds.width, y: 0))
let shape = CAShapeLayer()
shape.path = path.cgPath
layer.mask = shape
}
}
Example usage:
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.backgroundColor = .red
view.applyRadiusMaskFor(topLeft: 80, bottomLeft: 40, bottomRight: 30, topRight: 60)
Result: Radius applied image

addArc(withCenter) closing path

The following code:
let size = CGSize(width: 200, height: 30)
let rect = CGRect(origin: .zero, size: size)
let path1 = UIBezierPath()
path1.move(to: CGPoint(x: 10, y: 5))
path1.addLine(to: CGPoint(x: 180, y: 5))
path1.addArc(withCenter: CGPoint(x: 180, y: 20), radius: 15,
startAngle: (3.14159 / 2), endAngle: (3 * 3.14159 / 2), clockwise: false)
produces this:
Ok, am I missing something? I do not want to close this path. I never call path1.close(). I want to add another straight line from the end of the arc, not from the closed version of it. Basically, I don't want the half circle to be closed, how can I do that?
You need to start your arc at -90 degrees and end it at +90 degrees. You need also to change its direction. You need to do as follow:
path1.addArc(withCenter: CGPoint(x: 180, y: 20), radius: 15, startAngle: -.pi/2, endAngle: .pi/2, clockwise: true)
If you would like to complete the shape it would look like this:
let path1 = UIBezierPath()
path1.move(to: CGPoint(x: 10, y: 5))
path1.addLine(to: CGPoint(x: 180, y: 5))
path1.addArc(withCenter: CGPoint(x: 180, y: 20), radius: 15, startAngle: -.pi/2, endAngle: .pi/2, clockwise: true)
path1.addLine(to: CGPoint(x: 10, y: 35))
path1.addArc(withCenter: CGPoint(x: 10, y: 20), radius: 15, startAngle: .pi/2, endAngle:-.pi/2 , clockwise: true)
Hope this will help you to achieve your result
let size = CGRect(origin: .zero, size: CGSize(width : 200 , height : 30))
let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 100))
path.addLine(to: CGPoint(x: 180, y: 100))
path.addArc(withCenter: CGPoint(x:180 , y: 85), radius: 15, startAngle: (3.14159 / 2), endAngle: (3 * 3.14159 / 2), clockwise: false)
path.addLine(to: CGPoint(x: 10, y: 70)) //y = radius * 2
Above code will draw this in your canvas .

Resources