[iOS] Side Menu 직접 만들어보자 (Programmatically)

David·2024년 1월 5일
0
post-thumbnail

프로젝트에서 Side Menu를 구현할 일이 있어 라이브러리를 사용하지 않고 직접 만들어봤습니다.

하단의 코드는 SideMenu가 될 뷰 컨트롤러입니다.
여기에서는 백그라운드와 corner Radius 정도만 설정해줬습니다.

class SideMenuViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.layer.cornerRadius = 20
        self.view.clipsToBounds = true
        
        self.view.backgroundColor = .blue.withAlphaComponent(0.3)
        
    }
    
}

SideMenu의 상위 뷰(여기서는 ViewController)에서 사용할 SideMenu ViewController와 SideMenu 등장 시 딤 처리할 dimmingView, sideMenu 버튼인 sideMenuButton을 선언해줍니다.

class ViewController: UIViewController {
    private var sideMenuViewController = SideMenuViewController()
    private var dimmingView: UIView?
    
    private lazy var sideMenuButton = UIImageView().then {
        $0.image = UIImage(systemName: "text.justify")
        $0.tintColor = .black
        
        let tap = UITapGestureRecognizer(target: self, action: #selector(presentSideMenu))
        $0.addGestureRecognizer(tap)
        $0.isUserInteractionEnabled = true
    }

}

viewDidLoad 에서 UI를 잡아줍니다.
sideMenu가 나타나있을 때, dim 처리 된 배경 클릭 시 sideMenu를 다시 사라지게 하기 위해 handleDimmingViewTap 이라는 제스처를 추가하였습니다.

override func viewDidLoad() {
        super.viewDidLoad()
        addDimmingView()
  
    }
    
    private func addDimmingView() {
        dimmingView = UIView(frame: self.view.bounds)
        dimmingView?.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        dimmingView?.isHidden = true
        view.addSubview(dimmingView!)
        
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDimmingViewTap))
        dimmingView?.addGestureRecognizer(tapGesture)
    }

handleDimmingViewTap에서 애니메이션을 통해 side menu를 사라지게 하였습니다.

@objc private func handleDimmingViewTap() {
        let sideMenuVC = self.sideMenuViewController
        
        UIView.animate(withDuration: 0.3, animations: {
            // 사이드 메뉴를 원래 위치로 되돌림.
            sideMenuVC.view.frame = CGRect(x: -self.view.frame.width, y: 0, width: self.view.frame.width, height: self.view.frame.height)
            // 어두운 배경 뷰를 숨김.
            self.dimmingView?.alpha = 0
        }) { (finished) in
            // 애니메이션이 완료된 후 사이드 메뉴를 뷰 계층 구조에서 제거.
            sideMenuVC.view.removeFromSuperview()
            sideMenuVC.removeFromParent()
            self.dimmingView?.isHidden = true
        }
    }

sideMenuButton 클릭 시 동작하는 presentSideMenu 입니다.
높이와 너비를 설정해서 sideMenu의 모양을 커스텀할 수 있습니다.
또한 사이드 메뉴의 크기, yPos, 사이드 메뉴가 나타나기 전 크기와 사이드 메뉴가 화면에 표시될 크기를 조정하시면 다양한 애니메이션을 구현할 수 있습니다.

@objc private func presentSideMenu() {
        let sideMenuVC = self.sideMenuViewController
        
        // 사이드 메뉴 뷰 컨트롤러를 자식으로 추가하고 뷰 계층 구조에 추가.
        self.addChild(sideMenuVC)
        self.view.addSubview(sideMenuVC.view)
        
        // 사이드 메뉴의 너비를 화면 너비의 80%로 설정.
        let menuWidth = self.view.frame.width * 0.8
        let menuHeight = self.view.frame.height
        let yPos = (self.view.frame.height / 2) - (menuHeight / 2) // 중앙에 위치하도록 yPos 계산

        
        // 사이드 메뉴의 시작 위치를 화면 왼쪽 바깥으로 설정.
        sideMenuVC.view.frame = CGRect(x: -menuWidth, y: yPos, width: menuWidth, height: menuHeight)
        
        // 어두운 배경 뷰를 보이게 합니다.
        self.dimmingView?.isHidden = false
        self.dimmingView?.alpha = 0
        
        UIView.animate(withDuration: 0.3, animations: {
            // 사이드 메뉴를 화면에 표시.
            sideMenuVC.view.frame = CGRect(x: 0, y: yPos, width: menuWidth, height: menuHeight)
            // 어두운 배경 뷰의 투명도를 조절.
            self.dimmingView?.alpha = 0.5
        })
    }


0개의 댓글