Search code examples
swifttabbariso

Customising UItababbar swift


Can anyone point me how could I achieve such design in the UITabbar. I have tried adding the back-ground Image, but that does not look like the design. Here the curve is extended beyond the frame of UITabbar, not sure how to add this views on top of active tabbar.

Tab bar with a curved top


Solution

  • Creating a custom TabBar from UITabBarController can be solved the problem. Instead of adding a direct image to the Tabbar, use an on the fly image using UIGraphicsBeginImageContext for selectedTabBackgroundImage.

    1. Create the image.
    2. Clip the top part round in the image

    Here is the example of the code.

    import UIKit
    
    class CustomTabBarViewController: UITabBarController {
        
        var topClipSize: CGFloat = 24.5 //Adjust based on the number of tabbar
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            let singleTabWidth: CGFloat = self.tabBar.frame.size.width / CGFloat((self.tabBar.items?.count)!)
            let singleTabSize = CGSize(width:singleTabWidth , height: self.tabBar.frame.size.height)
            // Create the backgound image
            let selectedTabBackgroundImage: UIImage = self.imageWithColor(color: .blue, size: singleTabSize)
            // Clip the top
            self.tabBar.selectionIndicatorImage = selectedTabBackgroundImage.roundTopImage(topClipSize: topClipSize)
        }
        
        func imageWithColor(color: UIColor, size: CGSize) -> UIImage {
            if size.height > 55 {
                topClipSize = 30.0  // iPhone 8 tabbar height is 53 and iPnone X is 83 - We need more space on top.
            }
            let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height + topClipSize)
            UIGraphicsBeginImageContext(rect.size)
            let context = UIGraphicsGetCurrentContext()
            context!.setFillColor(color.cgColor)
            context!.fill(rect)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            
            return image!
        }
    }
    
    extension UIImage {
        func roundTopImage(topClipSize: CGFloat) -> UIImage {
        let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.size)
        let rectBounds: CGRect = CGRect(x: rect.origin.x, y: rect.origin.y + (topClipSize * 2), width: rect.size.width, height: rect.size.height - (topClipSize * 2))
        let ovalBounds: CGRect = CGRect(x: rect.origin.x - topClipSize, y: rect.origin.y, width: rect.size.width + (topClipSize * 2), height: rect.size.height)
        UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
        let rectPath = UIBezierPath(rect: rectBounds)
        let ovalPath = UIBezierPath(ovalIn: ovalBounds)
        rectPath.append(ovalPath)
        rectPath.addClip()
        self.draw(in: rect)
        return UIGraphicsGetImageFromCurrentImageContext()!
    }
    }
    

    Here is the output:

    enter image description here