NavigationBar 정리

dev_will_d·2023년 4월 24일
1

오늘은 앱을 개발할때 자주 사용하는 NavigationBar에 대해서 정리하는 시간을 갖도록 하겠다.

문제

  1. NavigationBar Title은 어떻게 처리 할 것인가?
  2. NavigationBar의 속성과 Right, Left에 아이콘 배치는 어떻게 할 것 인가.
    • Icon의 Right, Left 여백은 어떻게 할 것인가
    • Icon이 여러개라면 사이의 여백은 어떻게 할 것인가
    • Icon을 탭했을때 이벤트는 어떻게 처리 할 것인가

해결

  1. NavigationBar Title 설정
  • BaseViewController
  • MainViewController

  • DetailViewController

BaseViewController는 생명주기 및 ViewController의 속성을 공통으로 관리하는 기반이 되는 ViewController 이다. 이 BaseViewController를 상속 받은 각각의 ViewController에서 자신이 가져야 할 Navigation Title에 대해서 override하여 navTitle을 설정한다.

  1. NavigationBar의 속성과 Right, Left에 아이콘 배치는 어떻게 할 것 인가.
  • NavigationBar 초기 설정
import Foundation
import UIKit
import RxSwift
import RxCocoa



class NavigationManager {
...
    
    static func initNavigation(
        _ backImgName : String      = "back",
        _ backgroundColor : UIColor = .white,
        _ itemColor : UIColor       = .black,
        _ fontColor : UIColor       = .black,
        _ fontName : String         = "Helvetica Neue",
        _ fontSize : CGFloat        = 16
    ) {
        
        /*
         iOS 애플리케이션 전체에서 UINavigationBar 객체의 속성을
         설정 할 수 있는 인스턴스
         */
        let appearance = UINavigationBar.appearance()
        
        /*
         UINavigationBar 하단에 불투명한 그림자 표시에 관한 속성
         */
        appearance.shadowImage = UIImage()
        
        /*
         뒤로가기 이미지에 대한 속성
         */
        appearance.backIndicatorImage = UIImage(named: "back")
        appearance.backIndicatorTransitionMaskImage = UIImage(named: "back")
       
        /*
         NavigationBar 투명도에 대한 속성
         */
        appearance.isTranslucent = true
        
        /*
         탭바의 배경화면을 설정하는 속성
         */
        appearance.barTintColor = backgroundColor
        
        /*
         NavigationBar 탭바의 아이템 색깔을 설정하는 속성
         */
        appearance.tintColor = itemColor
        
        /*
         title font를 지정
         */
        appearance.titleTextAttributes = [
            NSAttributedString.Key.foregroundColor : fontColor,
            NSAttributedString.Key.font : UIFont(name: fontName, size: fontSize)!
        ]
    }
    ...
}
    

NavigationManager라는 NavigationBar을 관리하는 class를 하나 만들었다 이 중 initNavigation 이라는 static 함수는 NavigationBar Appearance를 통해서 Navigation Bar의 Background Color나 BackButtonImage와 같은 초기 설정을 담당하는 함수이다. 코드는 위와 같다.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool

이 함수는 앱 초기에 호출되는 application 함수에서 호출 한다.
이 후에 변경하고 싶으면 initNavigation 함수만 관리하면 된다.

  • Icon 배치와 버튼 탭 처리
class NavigationManager {
    var disposeBag = DisposeBag()
    
    ...
    ![](https://velog.velcdn.com/images/will_d/post/01df1f3d-bda4-442a-83c6-4d0b9d279a7f/image.png)

    func setItem(
        itemName : String,
        itemSize : Int = 24,
        padding : CGFloat = 0,
        _ tap : @escaping (UIView) -> Void
    ) -> [UIBarButtonItem] {
        let fixedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
        /*
         iOS에서 기본 Right, Left 여백 16
         */
        fixedSpace.width = padding
        
        let view = UIImageView().then {
            /*
             Icon 사이즈 및 Icon Img 설정
             */
            $0.image = UIImage(named: itemName)
            $0.snp.makeConstraints {
                $0.width.height.equalTo(itemSize)
            }
        }
        
        /*
         버튼 탭
         NavigationManager을 ViewController의 멤버로 생성한다.
         멤버로 생성하여 ButtonTap의 Observer를 ViewController와 생명주기와 일치 시킨다.
         */
        view.rx.tapGesture()
            .when(.recognized)
            .bind(onNext : { _ in
                tap(view)
            })
            .disposed(by: disposeBag)
        
        return [fixedSpace, UIBarButtonItem(customView: view)]
    }
    
    func setItems(
        itemNames : [String],
        itemSize : Int = 24,
        ltPadding : CGFloat = 0,
        betweenPadding : CGFloat = 0,
        _ tap : @escaping (Int) -> Void
    ) -> [UIBarButtonItem] {
        if itemNames.count > 1 {
            let fixedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
            /*
             iOS에서 기본 Right, Left 여백 16
             iOS에서 기본 Icon 사이의 여백 8
             */
            fixedSpace.width = ltPadding
            var result = itemNames.enumerated().map { index, itemName in
                let view = UIImageView().then {
                    /*
                     Icon 사이즈 및 Icon Img 설정
                     */
                    $0.image = UIImage(named: itemName)
                    $0.snp.makeConstraints {
                        $0.width.height.equalTo(itemSize)
                    }
                }
                
                /*
                 버튼 탭
                 NavigationManager을 ViewController의 멤버로 생성한다.
                 멤버로 생성하여 ButtonTap의 Observer를 ViewController와 생명주기와 일치 시킨다.
                 */
                view.rx.tapGesture()
                    .when(.recognized)
                    .bind(onNext : { _ in
                        /*
                         index를 delegate에 전달한다
                         사용을 한다면 Index를 통해서 어떠한 icon을 선택했는지
                         판단이 가능하다.
                         */
                        tap(index)
                    })
                    .disposed(by: disposeBag)
                
                return UIBarButtonItem(customView: view)
            }
            
            
            /*
             Icon 사이의 여백을 결정하는 로직
             */
            for i in 0..<result.count + (result.count - 1) {
                if i % 2 == 1 {
                    let betweenSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
                    betweenSpace.width = betweenPadding - 8
                    result.insert(betweenSpace, at: i)
                }
            }
            
            result.insert(fixedSpace, at: 0)
            return result
        } else {
            return []
        }
    }
    
}

Icon 배치와 버튼 탭 처리는 setItem, setItems 함수를 통해서 구현했다. 이 setItem, setItems 함수는
IconSize, IconTap, Icon 오른쪽, 왼쪽 여백, Icon과 Icon 사이의 여백의 값을 조정하는 로직이 존재한다.
실제 사용을 할때는 NavigationItem의 오른쪽에 배치할 것인지 왼쪽에 배치할것인지만 결정해주면 된다. 실제 사용 코드는 아래와 같다. [setItem 사용 방법도 아래와 비슷하다.]

결과

오늘은 이렇게 iOS에서 자주 사용하는 NavigationBar에 대해서 정리를 해봤다.

위와 같은 방법으로 정리를 해 놓으면 나중에 유지 보수 할떄 좀더 수월 하게 할 수 있을것 같아 정리해봤다.

profile
질문의 질이 답의 질을 결정한다.

0개의 댓글