skip to Main Content

I have a tabBarController with a curved tabBar via caShapeLayer.

My issue is the rectangular frame tabBar clips the bottom of children viewControllers.

My goal/hope was to go under and clip the bottom by the curved frame. See image for reference.

enter image description here

Any guidance would be really appreciated.

Code for Curved TabBar in TabBarController

override func viewDidLoad() {
super.viewDidLoad()
    
self.view.backgroundColor = .blue
self.tabBar.backgroundColor = .clear
self.tabBar.barStyle = .default
self.tabBar.isTranslucent = false
self.tabBar.clipsToBounds = false
hideTabBarBorder()
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    addTabBarShape()
}

func addTabBarShape() {

let shapeLayer = CAShapeLayer()

let offset:CGFloat = tabBar.bounds.width/3.5
let bounds: CGRect = tabBar.bounds

let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height / 2), width: bounds.size.width, height: bounds.size.height / 2)

let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)
let ovalBounds: CGRect = CGRect(x: bounds.origin.x - (offset / 2), y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)

shapeLayer.path = rectPath.cgPath
shapeLayer.fillColor = .blue
shapeLayer.shadowPath =  rectPath.cgPath
shapeLayer.shadowColor = UIColor.black.cgColor
shapeLayer.shadowOpacity = 0.1
shapeLayer.shadowRadius = 20
shapeLayer.shadowOffset = CGSize(width: 0, height: -8)

shapeLayer.shouldRasterize = true
shapeLayer.rasterizationScale = UIScreen.main.scale

    if let oldShapeLayer = self.tabBarShapeLayer {
        self.tabBar.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
    } else {
        self.tabBar.layer.insertSublayer(shapeLayer, at: 0)
    }
    self.tabBarShapeLayer = shapeLayer
}

func hideTabBarBorder() {
    self.tabBar.backgroundImage = UIImage.from(color: Constants.style.darkBlue)
    self.tabBar.shadowImage = UIImage()
}

extension UIImage {
    static func from(color: UIColor) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()
    context!.setFillColor(color.cgColor)
    context!.fill(rect)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img!
    }
}

3

Answers


  1. Chosen as BEST ANSWER

    My workaround was drawing the curve at a higher y-point than the tabBar frame...


  2. This is because the child ViewController did not update its constraint, and it is referring to the same tabcontroller constraint. You just need to review the bottom constraint from the controller. I am using snapkit here to fix the constraint before the view appears. You can set the controller bottom margin equal to the superView and handle the tabbar offset inside your controller.

    This will basically ignore the presence of the tabbar at the bottom.

    import UIKit
    import SnapKit
    
    class SomeViewController: UIViewController {
        
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            updateConstraints()
        }
        
        func updateConstraints() {
            view.snp.makeConstraints { make in
                make.edges.equalToSuperview()
            }
        }
    }
    
    Login or Signup to reply.
  3. You have to set the backgroundImage to something not visible to make the view appear to be clipped by the tabbar.

    I am not sure why you are explicitly setting it to UIImage.from(color: Constants.style.darkBlue) in your example.

    The following + copying all your other code is working just fine for me:

        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            addTabBarShape()
            tabBar.backgroundImage = UIImage()
            tabBar.shadowImage = UIImage()
        }
    

    Also make sure that you connect the bottom anchor of the view (e.g. a UITableView) not to view.safeAreaLayoutGuide.bottomAnchor (like you normally would do) but rather to view.bottomAnchor to make it appear clipped by the tabBar.

    (changed some colors in that implementation but here you can see how it clips a UITableView)

    Screenshot with tabbar clipping a view

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search