관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] BaseNavigationController, 커스텀 NavigationController, setBackIndicatorImage, back 버튼, withAlignmentRectInsets 본문

iOS 응용 (swift)

[iOS - swift] BaseNavigationController, 커스텀 NavigationController, setBackIndicatorImage, back 버튼, withAlignmentRectInsets

jake-kim 2021. 9. 11. 02:14

커스텀 NavigationController 아이디어

  • 커스텀한 navigationBar와 Back 버튼 이미지를 새로 추가하여 사용
  • static func makeNavigationController(rootViewController:)로, 커스텀된 navigationController를 해당 클래스 내부에서 빌더를 통해 사용할 수 있도록 설정

커스텀 NavigationController 구현

  • BaseNavigationController 클래스 정의
class BaseNavigationController: UINavigationController {
    static func makeNavigationController(rootViewController: UIViewController) -> BaseNavigationController {
        let navigationController = BaseNavigationController(rootViewController: rootViewController)
        navigationController.modalPresentationStyle = .fullScreen

        return navigationController
    }
    
}
  • navigationController의viewDidLoad()에서 커스텀 스타일을 적용하는 메소드 호출하는 형태
// BaseNavigationController.swift

override func viewDidLoad() {
    super.viewDidLoad()

    // TODO: 아직 안구현
    setNavigationBarAppearance()
}
  • setNavigationBarAppearance() 메소드에서 필요한 것들 정의
  • backButtonImage 정의
    • 주의: UIImage객체에다가 withAlignmentRectInsets()을 통해 backbutton의 위치 지정

private var backButtonImage: UIImage? {
    return UIImage(named: "button")?.withAlignmentRectInsets(UIEdgeInsets(top: 0.0, left: -12.0, bottom: -5.0, right: 0.0))
}
  • withAlignmentRectInsets(UIEdgeInsets(top: 0.0, left: -12.0, bottom: -5.0, right: 0.0)) 옵션 비교
    • edge에 -값을 주면 해당 edge 반대 방향으로 이동
    • edge에 +값을 주면 해당 edge 방향으로 이동
주지 않은 경우


준 경우
  • backbutton하단에 디폴트로 존재하는 "Back" 문구를 보이지 않도록 설정하는 UIBarButtonItemAppearance() 사용

private var backButtonAppearance: UIBarButtonItemAppearance {
    let backButtonAppearance = UIBarButtonItemAppearance()
    // backButton하단에 표출되는 text를 안보이게 설정
    backButtonAppearnce.normal.titleTextAttributes = [.foregroundColor: UIColor.clear, .font: UIFont.systemFont(ofSize: 0.0)]

    return backButtonAppearance
}

 

  • setNavigationBarAppearance() 정의
    let appearance = UINavigationBarAppearance()
    appearance.backgroundColor = .gray
    appearance.shadowColor = .clear
    /// transitionMaskImage파라미터: push되거나 pop될때의 backButton 마스크 이미지
    appearance.setBackIndicatorImage(backButtonImage, transitionMaskImage: backButtonImage)
    appearance.backButtonAppearance = backButtonAppearance

    navigationBar.standardAppearance = appearance
    navigationBar.compactAppearance = appearance
    navigationBar.scrollEdgeAppearance = appearance
    navigationBar.isTranslucent = false
    /// navigationItem의 버튼 색상을 .white로 지정
    navigationBar.tintColor = .white
}
  • cf) 사용하는 쪽에서 backButton 숨기는 방법
navigationItem.hidesBackButton = false

사용

// SceneDelegate.swift

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    window = UIWindow(windowScene: windowScene)
    window?.rootViewController = BaseNavigationController(rootViewController: ViewController())
    window?.makeKeyAndVisible()
}

title의 위치를 중앙으로 하지않고 커스텀하는 방법

backButton과 32.0만큼 떨어진 타이틀

  • 아이디어
    • leftBarButtonItems에 [UIBarButtonItem]을 대입할때, 객체중에 padding값을 갖는 UIBarButtonItem삽입
// method

static func getCustomBarButtonItems(isShowBackButton: Bool, labelText: String) -> [UIBarButtonItem]
// 사용

navigationItem.leftBarButtonItems = BaseNavigationController.getCustomBarButtonItems(isShowBackButton: true,
                                                                                             labelText: "커스텀 타이틀")
  • 메소드 구현
  • [UIBarButtonItem]에 들어갈 backButton, 패딩값을 갖는 IUBarButtonItem, 오른쪽편에 들어갈 label 정의
// backButton

static let backButton: UIButton = {
    let button = UIButton()
    button.setImage(UIImage(named: "button"), for: .normal)

    return button
}()
// 패딩값을 갖는 UIBarButtonItem

private static let paddingBarButtonItem: UIBarButtonItem = {
    let spaceBarButtonItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
    spaceBarButtonItem.width = 32.0 /// 32.0만큼 왼쪽 버튼과 여백

    return spaceBarButtonItem
}()
// titleLabel

static let titleLabel: UILabel = {
    let label = UILabel()
    label.font = .systemFont(ofSize: 16.0, weight: .bold)
    label.textColor = .white
    label.textAlignment = .left

    return label
}()
  • 위 값을 가지고 [UIBarButtonItem]을 리턴하는 메소드 구현
static func getCustomBarButtonItems(isShowBackButton: Bool, labelText: String) -> [UIBarButtonItem] {

    var barButtonItems = [UIBarButtonItem]()

    if isShowBackButton {
        let backButtonItem = UIBarButtonItem(customView: backButton)
        barButtonItems.append(backButtonItem)
        barButtonItems.append(paddingBarButtonItem)
    }
    titleLabel.text = labelText
    let labelBarButtonItem = UIBarButtonItem(customView: titleLabel)
    barButtonItems.append(labelBarButtonItem)

    return barButtonItems
}
  • 사용
navigationItem.leftBarButtonItems = BaseNavigationController.getCustomBarButtonItems(isShowBackButton: true,
                                                                                     labelText: "커스텀 타이틀")

* 전체 소스 코드: https://github.com/JK0369/BaseNavigationViewController

 

* 참고

- withAlignmentRectInsets: https://developer.apple.com/documentation/uikit/uiimage/1624100-withalignmentrectinsets

Comments