3

How can I create the following tab (see attached) in swift?enter image description here

Chris Hansen
  • 7,813
  • 15
  • 81
  • 165

5 Answers5

9

Based on this answer: https://stackoverflow.com/a/58941827/5753078

Subclass UITabBar like following. This solution takes into account the safeArealayout guides for devices with notch. I find 65 to be a sweet spot height for top rounded tabBar.

@IBDesignable class TabBarWithCorners: UITabBar {
    @IBInspectable var color: UIColor?
    @IBInspectable var radii: CGFloat = 15.0

    private var shapeLayer: CALayer?

    override func draw(_ rect: CGRect) {
        addShape()
    }

    private func addShape() {
        let shapeLayer = CAShapeLayer()

        shapeLayer.path = createPath()
        shapeLayer.strokeColor = UIColor.gray.withAlphaComponent(0.1).cgColor
        shapeLayer.fillColor = color?.cgColor ?? UIColor.white.cgColor
        shapeLayer.lineWidth = 2
        shapeLayer.shadowColor = UIColor.black.cgColor
        shapeLayer.shadowOffset = CGSize(width: 0   , height: -3);
        shapeLayer.shadowOpacity = 0.2
        shapeLayer.shadowPath =  UIBezierPath(roundedRect: bounds, cornerRadius: radii).cgPath
        

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

        self.shapeLayer = shapeLayer
    }

    private func createPath() -> CGPath {
        let path = UIBezierPath(
            roundedRect: bounds,
            byRoundingCorners: [.topLeft, .topRight],
            cornerRadii: CGSize(width: radii, height: 0.0))

        return path.cgPath
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        self.isTranslucent = true
        var tabFrame            = self.frame
        tabFrame.size.height    = 65 + (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? CGFloat.zero)
        tabFrame.origin.y       = self.frame.origin.y +   ( self.frame.height - 65 - (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? CGFloat.zero))
        self.layer.cornerRadius = 20
        self.frame            = tabFrame



        self.items?.forEach({ $0.titlePositionAdjustment = UIOffset(horizontal: 0.0, vertical: -5.0) })


    }

}

Result should look like this: 2

Frankenxtein
  • 483
  • 7
  • 18
  • 3
    Great answer! One thing though, even it's not that crucial. That annoying 'key window' warning fix: just replace: `UIApplication.shared.keyWindow?` with: `UIApplication.shared.windows.filter {$0.isKeyWindow}.first?` – nja Oct 01 '20 at 08:25
  • Good answer! But for my case it the area behind the rounded corners are opague and can't see the contents below it. I have to set both self.shadowImage = UIImage() and self.backgroundImage = UIImage() so that the backdrop view created by tabBar automatically becomes fully transparent. Took me 2 days to figure this out, hope this helps someone. – Bruce Dec 11 '20 at 02:21
  • This works great! How would you move the individual images up? The titles move up but are now too close to the icons. – TrevPennington Jan 06 '21 at 15:04
  • This is nice but is not working properly, on the corners is showing some white space. If I try to put some view under the tab bar, it will cover it with some white layer on the corners. Also, it's going a lot upwards. The buttons I had with a bottom constraint with 14-16 pts, now the tab bar is touching them. – Emm Nov 17 '21 at 14:34
4

I am guessing this is UITabBar so you can either set rounded corners somewhere in code like this:

layer.cornerRadius = 30
layer.masksToBounds = true
layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]

The first controls the rounding and the maskedCorners specifies to only round top left and top right corners.

Or create subclass and set those properties in init.

Filip
  • 1,824
  • 4
  • 18
  • 37
1

Pretty easy; you create your view like this:

let theView: UIView = {
   let v = UIView()
   v.translatesAutoresizingMaskIntoConstraints = false
   v.backgroundColor = .white
   v.layer.cornerRadius = 30
   v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
   return v
}()

You can change cornerRadius to whatever value you like. The code above gives your view rounded corners at the top, like in your picture.

Chris
  • 1,828
  • 6
  • 40
  • 108
0

The Best Way is to subclass UITabBar class and draw your classic tabBar there with shadows you want to add Here is a nice tutorial for Quick start

Another workaround if you don't need total control you can do it like this

tabBar.layer.masksToBounds = true 
tabBar.isTranslucent = true  
tabBar.layer.cornerRadius = 10 
self.tabBar.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
Jawad Ali
  • 13,556
  • 3
  • 32
  • 49
0

Try this

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: view.frame.width, height: tabBar.frame.height), cornerRadius: 15)
    let mask = CAShapeLayer()
    mask.path = path.cgPath
    tabBar.layer.mask = mask

}
Sreekanth M
  • 151
  • 1
  • 6