ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Swift/Study] 탭바 모양 커스텀 하기 (둥글게 휘게하고 동그란 버튼 넣기)
    Study/ios 2023. 7. 6. 21:11

    내가 이 탭바 디자인을 위해 여러 블로그를 찾다가 외국 블로그에서 찾아 해결했었는데

    방법을 간단하게 공유해 보려고 한다.

     

     

    결과 화면

     

    (탭바 컨트롤러에 연결된 2개의 뷰 컨트롤러가 있다고 가정)

     

    먼저 다음과 같은 클래스를 정의 한다.

    import UIKit
    
    class MyTabBarCtrl: UITabBarController, UITabBarControllerDelegate {
        
        // UITabBarControllerDelegate를 요구하는 initializer를 추가합니다.
        required init(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)!
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // 뷰 컨트롤러의 delegate를 self로 설정하여 MyTabBarCtrl이 UITabBarControllerDelegate 프로토콜을 처리할 수 있도록 합니다.
            self.delegate = self
        }
    }

     

     

    스토리보드에서 탭바 컨트롤러를 선택하고 커스텀 클래스를 위 클래스로 연결한다.

     

     

    그리고 탭바를 커스텀하여 그리기 위해 다음과 같은 클래스를 정의한다.

    import UIKit
    
    @IBDesignable
    class MyTabBar: UITabBar {
        private var shapeLayer: CALayer?
        
        // 탭 바의 모양을 그리기 위한 Shape Layer를 추가합니다.
        private func addShape() {
            let shapeLayer = CAShapeLayer()
            shapeLayer.path = createPath()
            shapeLayer.strokeColor = UIColor.lightGray.cgColor
            shapeLayer.fillColor = UIColor.white.cgColor
            shapeLayer.lineWidth = 1.0
            
            // 그림자 설정
            shapeLayer.shadowOffset = CGSize(width: 0, height: 0)
            shapeLayer.shadowRadius = 10
            shapeLayer.shadowColor = UIColor.gray.cgColor
            shapeLayer.shadowOpacity = 0.3
            
            // 기존의 Shape Layer를 교체하거나 새로운 Shape Layer를 추가합니다.
            if let oldShapeLayer = self.shapeLayer {
                self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
            } else {
                self.layer.insertSublayer(shapeLayer, at: 0)
            }
            
            self.shapeLayer = shapeLayer
        }
        
        override func draw(_ rect: CGRect) {
            // draw(_:) 메서드가 호출되면 탭 바의 모양을 그리기 위한 Shape Layer를 추가합니다.
            self.addShape()
        }
        
        // 탭 바의 모양을 정의하기 위한 경로를 생성합니다.
        func createPath() -> CGPath {
            let height: CGFloat = 37.0
            let path = UIBezierPath()
            let centerWidth = self.frame.width / 2
            
            // 경로를 그립니다.
            path.move(to: CGPoint(x: 0, y: 0))
            path.addLine(to: CGPoint(x: (centerWidth - height * 2), y: 0))
            
            path.addCurve(to: CGPoint(x: centerWidth, y: height),
                          controlPoint1: CGPoint(x: (centerWidth - 30), y: 0),
                          controlPoint2: CGPoint(x: centerWidth - 35, y: height))
            
            path.addCurve(to: CGPoint(x: (centerWidth + height * 2), y: 0),
                          controlPoint1: CGPoint(x: centerWidth + 35, y: height),
                          controlPoint2: CGPoint(x: (centerWidth + 30), y: 0))
            
            path.addLine(to: CGPoint(x: self.frame.width, y: 0))
            path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height))
            path.addLine(to: CGPoint(x: 0, y: self.frame.height))
            path.close()
            
            return path.cgPath
        }
        
        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            // 탭 바의 클립 영역 안에서만 버튼을 탐지할 수 있도록 구현합니다.
            guard !clipsToBounds && !isHidden && alpha > 0 else { return nil }
            
            // 서브뷰들을 탭 바의 위에서부터 역순으로 탐색합니다.
            for member in subviews.reversed() {
                let subPoint = member.convert(point, from: self)
                
                // 버튼을 탐지하면 해당 뷰를 반환합니다.
                guard let result = member.hitTest(subPoint, with: event) else {
                    continue
                }
                
                return result
            }
            
            return nil
        }
    }

    탭바의 가운데가 움푹 파인 것처럼 다시 그렸다.

     

     

    그리고 탭바를 선택하여 커스텀 클래스 연결

     

     

    그러면 다음과 같은 탭바의 모양을 볼 수 있다.

     

     

    그리고 저 움푹 파인 곳에 들어갈 버튼을 추가하여야 한다.

    스토리 보드에서 그냥 버튼을 추가하면 문제가 생긴다.

    탭바의 영역에 포함된 버튼은 터치되지 않는다.

    따라서 코드로 버튼을 탭바 위에 추가하여야 한다.

     

     

    먼저 탭바 변수를 선언

    var tabBar: UITabBar?

     

    현재 탭바 컨트롤러의 탭바를 가져와 위 변수에 저장한다.

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        guard let tabBarController = self.tabBarController else {
            return
        }
        // 탭바를 가져와 저장
        tabBar = tabBarController.tabBar
    }

     

    저장한 탭바 변수를 가지고 다음과 같은 커스텀 버튼을 탭바 위에 추가

    func makeButton() {
        let button = UIButton(type: .custom)
        button.frame = CGRect(x: 151, y: -50, width: 91, height: 91)
        button.setImage(UIImage(named: "icon_plus.png"), for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    
        if let tabBar = self.tabBarController?.tabBar {
            tabBar.addSubview(button)
        }
    }
    
    @objc func buttonTapped() {
        print("touch")
    }

     

     

    그리고 위 함수를 포함해서 실행해주면?

    위와 같이 이쁘게 모양을 구성할 수 있다!

Designed by Tistory.