How to add selected corner radius and shadow for UIView in swift - swift

Can someone please help me with this question in iOS Swift. I have an UI view with drop shadow effect. I need corner radius for 3 corners except for one corner. Any help is appreciated.
Thanks,
Dharani

You can use extension on UIView:
Here is a sample I created on Playgrounds:
let view = UIView()
extension UIView {
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
}
}
// customize where you want your roundCorners on your UIView
view.roundCorners([.topLeft, .topRight, .bottomRight], radius: 10)

Related

How can i achieve this kind of corner redius with shadow view iOS swift?

I am trying to make a design which have top left corner radius and bottom right corner radius with shadow. I am able to make shadow also corner radius around the view.But when i am trying to give corner radius only to side shadow or radius is not showing. Hare what i have done
extension UIview {
//corner radius function
func roundCornersForView(corners:UIRectCorner, radius: CGFloat) {
DispatchQueue.main.async {
let path = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
}
func setShadow(){
self.layer.masksToBounds = false
// set the shadow properties
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 1.0)
self.layer.shadowOpacity = 0.2
self.layer.shadowRadius = 4.0
self.roundCornersForView(corners: [.topLeft, .bottomRight], radius: 20)
}
}
/// finally call it table cell
cell?.BackView.setShadow()
here is the design what i want to do
1) Why write a separate function to draw rect and then apply cornerRadius mask to your view? Replace the function's contents with:
yourView.layer.masksToBounds = true
yourView.layer.cornerRadius = 20
yourView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]
2) Once you mask your view's corners and set its masksToBounds property to true, you can set shadow to the view's layer and it will automatically wrap around the rounded corners as you desire:-
yourView.layer.shadowOffset = CGSize(width: 0, height: -0.5)
yourView.layer.shadowRadius = 1
yourView.layer.shadowColor = UIColor(red:0.01, green:0.05, blue:0.09, alpha:0.18).cgColor
yourView.layer.shadowOpacity = 0.8
3) It's advised to play with your cell's UI attributes(a subview's cornerRadius and shadow in your case) in the cell class's awakeFromNib() or an init() method rather than in your delegate methods as they get called a lot of times and hence break the whole point of reusability
Have tested the code to apply shadow and it works fine for me. Hope this helps!

Drawing shapes with constraints swift 4

i'm trying to learn how to draw shapes and animate it, i succeeded at both and i managed to draw shapes in the center of my screen and in alignment to each other, but when i change my simulator to any device other than my view as device they jump out of the center of the screen, is there any way to set constraints to my drawn shapes so that they are always in the center?
here is my code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// rect
let layer = CAShapeLayer()
let bounds = CGRect(x: 60, y: 200, width: 250, height: 250)
layer.path = UIBezierPath(roundedRect: bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 20, height: 20)).cgPath
layer.strokeColor = UIColor.white.cgColor
layer.fillColor = UIColor.clear.cgColor
layer.lineWidth = 4
view.layer.addSublayer(layer)
let rectAnimation = CABasicAnimation(keyPath: "strokeEnd")
rectAnimation.fromValue = 0
rectAnimation.toValue = 1
rectAnimation.duration = 2
layer.add(rectAnimation, forKey: "line")
}
A powerful tool to give constraint is Masonry, you will really appreciate it. It's super easy for setting constraints and for animating them;
Else you can set your x and y "bounds" coordinates to be at centerX and centerY too

Round Top Corners of a UIView in Swift

I am trying to round top corners using below code
func roundCorners(corners:UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
use myView.roundCorners(corners:[.topLeft, .topRight], radius: radius)
But it's rounding one side of the view:
this is in a tableView sectionHeader if I scroll down then up it rounded using same code:
And also top discount view corners are rounded using same function.
thank's for help.
Update
if I fix the width on the view then it works fine.
iOS 11 introduced maskedCorners which results in smoother and better quality results. You can still use the UIRectCorner in the function call and have it translated to CACornerMask:
Swift 5:
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
if #available(iOS 11.0, *) {
clipsToBounds = true
layer.cornerRadius = radius
layer.maskedCorners = CACornerMask(rawValue: corners.rawValue)
} else {
let path = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
)
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
}
Solved this with the help of #Paolo and below is the working code.
Swift 3.2
extension UIView {
func roundCorners(corners:UIRectCorner, radius: CGFloat) {
DispatchQueue.main.async {
let path = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
}
}
for calling this function use below line and mention which corners you want to round
self.myView.roundCorners(corners: [.topLeft, .topRight, .bottomLeft, .bottomRight], radius: 8.0)

How do I create a UIView with top corners rounded, bottom corners normal, and a border around this whole view?

This is what I'm getting with this code
private func setupBorders(){
let path = UIBezierPath(roundedRect: mainTableView.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 20, height: 20))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
mainTableView.layer.mask = maskLayer
mainTableView.layer.borderColor = UIColor.darkGray.cgColor
mainTableView.layer.borderWidth = 1.0
}
MainTableView is a uiview containing the notepad table and the table header. If I can get it to work for any UIView then it will work for this one. Much appreciation to anyone who can help!
Edit: In case its not clear, the problem is the border disappears on the rounded corners.
A mask layer is not enough to solve your requirement, because the layer border will not respect to the layer mask. Instead you should create a view for drawing the backgound and the border, and it should clip its contents along the border, too.
In storyboard drag a UIView to your ViewController, set constrains as you want, link it to NewView and try this,
import UIKit
import QuartzCore
class ViewController: UIViewController{
#IBOutlet var NewView :UIView!
override func viewDidLoad() {
super.viewDidLoad()
let screenSize: CGRect = UIScreen.mainScreen().bounds
let HeightFloat :CGFloat = screenSize.height - 60
let WidthFloat :CGFloat = screenSize.width - 50
let NewRect :CGRect = CGRectMake(10, 20, WidthFloat, HeightFloat)
let maskPath = UIBezierPath(roundedRect: NewRect,
byRoundingCorners: [.TopLeft, .TopRight],
cornerRadii: CGSize(width: 10, height: 10))
let shape = CAShapeLayer()
shape.path = maskPath.CGPath
shape.fillColor = UIColor.clearColor().CGColor
shape.strokeColor = UIColor.darkGrayColor().CGColor
shape.lineWidth = 2
shape.lineJoin = kCALineJoinRound
NewView.layer.mask = shape
}
}
You will get your output,

Cut a circle out of a UIView using mask [duplicate]

This question already has answers here:
How can I 'cut' a transparent hole in a UIImage?
(4 answers)
Closed 6 years ago.
In my app I have a square UIView and I want to cut a hole/notch out of the top of. All the tutorials online are all the same and seemed quite straightforward but every single one of them always delivered the exact opposite of what I wanted.
For example this is the code for the custom UIView:
class BottomOverlayView: UIView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
drawCircle()
}
fileprivate func drawCircle(){
let circleRadius: CGFloat = 80
let topMidRectangle = CGRect(x: 0, y: 0, width: circleRadius*2, height: circleRadius*2)
let circle: CAShapeLayer = CAShapeLayer()
circle.position = CGPoint(x: (frame.width/2)-circleRadius, y: 0-circleRadius)
circle.fillColor = UIColor.black.cgColor
circle.path = UIBezierPath(ovalIn: topMidRectangle).cgPath
circle.fillRule = kCAFillRuleEvenOdd
self.layer.mask = circle
self.clipsToBounds = true
}
}
Here is what I hope to achieve (the light blue is the UIView, the dark blue is the background):
But here is what I get instead. (Every single time no matter what I try)
I'm not sure how I would achieve this, aside from making a mask that is already the exact shape that I need. But if I was able to do that then I wouldn't be having this issue in the first place. Does anyone have any tips on how to achieve this?
EDIT: The question that this is supposedly a duplicate of I had already attempted and was not able to get working. Perhaps I was doing it wrong or using it in the wrong context. I wasn't familiar with any of the given methods and also the use of pointers made it seem a bit outdated. The accepted answer does a much better job of explaining how this can be implemented using much more widely used UIBezierPaths and also within the context of a custom UIView.
I'd suggest drawing a path for your mask, e.g. in Swift 3
// BottomOverlayView.swift
import UIKit
#IBDesignable
class BottomOverlayView: UIView {
#IBInspectable
var radius: CGFloat = 100 { didSet { updateMask() } }
override func layoutSubviews() {
super.layoutSubviews()
updateMask()
}
private func updateMask() {
let path = UIBezierPath()
path.move(to: bounds.origin)
let center = CGPoint(x: bounds.midX, y: bounds.minY)
path.addArc(withCenter: center, radius: radius, startAngle: .pi, endAngle: 0, clockwise: false)
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
path.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
path.close()
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
Note, I tweaked this to set the mask in two places:
From layoutSubviews: That way if the frame changes, for example as a result of auto layout (or by manually changing the frame or whatever), it will update accordingly; and
If you update radius: That way, if you're using this in a storyboard or if you change the radius programmatically, it will reflect that change.
So, you can overlay a half height, light blue BottomOverlayView on top of a dark blue UIView, like so:
That yields:
If you wanted to use the "cut a hole" technique suggested in the duplicative answer, the updateMask method would be:
private func updateMask() {
let center = CGPoint(x: bounds.midX, y: bounds.minY)
let path = UIBezierPath(rect: bounds)
path.addArc(withCenter: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
let mask = CAShapeLayer()
mask.fillRule = .evenOdd
mask.path = path.cgPath
layer.mask = mask
}
I personally find the path within a path with even-odd rule to be a bit counter-intuitive. Where I can (such as this case), I just prefer to just draw the path of the mask. But if you need a mask that has a cut-out, this even-odd fill rule approach can be useful.