I would like to add corner radius & shadow on my navigation controller. I know how to do separately, but when I try to put both at the same time, only one is applied. I tried with CALayer, without success.
An Image to illustrated what I want
I would like to add corner radius & shadow on my navigation controller. I know how to do separately, but when I try to put both at the same time, only one is applied. I tried with CALayer, without success.
An Image to illustrated what I want
Here is the code,
// 1. Enable prefersLargeTitles and title
self.navigationController?.navigationBar.prefersLargeTitles = true
self.title = "Title"
// 2. Add left, right bar buttons
let leftBtn = UIBarButtonItem(title: "Edit", style: .done, target: self, action: #selector(item))
let rtBtn = UIBarButtonItem(title: "Add", style: .done, target: self, action: #selector(item))
self.navigationItem.rightBarButtonItem = rtBtn
self.navigationItem.leftBarButtonItem = leftBtn
//3. Change default navbar to blank UI
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.tintColor = UIColor.orange
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.backgroundColor = UIColor.white
//4. Add shadow and cirner radius to navbar
let shadowView = UIView(frame: CGRect(x: 0, y: -20,
width: (self.navigationController?.navigationBar.bounds.width)!,
height: (self.navigationController?.navigationBar.bounds.height)! + 20))
shadowView.backgroundColor = UIColor.white
self.navigationController?.navigationBar.insertSubview(shadowView, at: 1)
let shadowLayer = CAShapeLayer()
shadowLayer.path = UIBezierPath(roundedRect: shadowView.bounds, byRoundingCorners: [.bottomLeft , .bottomRight , .topLeft], cornerRadii: CGSize(width: 20, height: 20)).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowColor = UIColor.darkGray.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: 2.0, height: 2.0)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
shadowView.layer.insertSublayer(shadowLayer, at: 0)
Output:
You can get height dynamically using
self.navigationController?.view.safeAreaInsets.top
it will return 44 for iPhone X and 20 for iPhone 8
Code
var offset : CGFloat = (self.navigationController?.view.safeAreaInsets.top ?? 20)
let shadowView = UIView(frame: CGRect(x: 0, y: -offset,
width: (self.navigationController?.navigationBar.bounds.width)!,
height: (self.navigationController?.navigationBar.bounds.height)! + offset))
Output iPhoneX
Best Way is add this extension in your class add extension at the end of your class and Add shadow as well corner radius to any view as well to navigation controller :)
image shows the Xcode
view
Output of navigation controller
extension UIView {
@IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
@IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
@IBInspectable
var borderColor: UIColor? {
get {
if let color = layer.borderColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.borderColor = color.cgColor
} else {
layer.borderColor = nil
}
}
}
@IBInspectable
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowRadius = newValue
}
}
@IBInspectable
var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set {
layer.shadowOpacity = newValue
}
}
@IBInspectable
var shadowOffset: CGSize {
get {
return layer.shadowOffset
}
set {
layer.shadowOffset = newValue
}
}
@IBInspectable
var shadowColor: UIColor? {
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.shadowColor = color.cgColor
} else {
layer.shadowColor = nil
}
}
}
}
To solve this issue use custom UIView. See the following code and output as you expected, I hope this helps you.
Using cornerRadius
and maskedCorners
to you can set specific corner radius.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
navigationView.layer.cornerRadius = 20
navigationView.layer.maskedCorners = [.layerMinXMaxYCorner , .layerMaxXMaxYCorner]
navigationView.addShadow(shadowColor: UIColor.gray.cgColor, shadowOffset: CGSize(width: 1, height: 2), shadowOpacity: 0.5, shadowRadius: 20)
}
Add Following extension
extension UIView {
@IBInspectable var shadow: Bool {
get {
return layer.shadowOpacity > 0.0
}
set {
if newValue == true {
self.addShadow()
}
}
}
@IBInspectable var cornerRadius: CGFloat {
get {
return self.layer.cornerRadius
}
set {
self.layer.cornerRadius = newValue
// Don't touch the masksToBound property if a shadow is needed in addition to the cornerRadius
if shadow == false {
self.layer.masksToBounds = true
}
}
}
func addShadow(shadowColor: CGColor = UIColor.black.cgColor,
shadowOffset: CGSize = CGSize(width: 1.0, height: 2.0),
shadowOpacity: Float = 0.4,
shadowRadius: CGFloat = 3.0) {
layer.shadowColor = shadowColor
layer.shadowOffset = shadowOffset
layer.shadowOpacity = shadowOpacity
layer.shadowRadius = shadowRadius
}
}