Login과 Onboarding 화면을 모두 마쳤으니, 본격적인 Main화면을 구성하려고 한다.
이전 Storyboard 방식으로 개발을 할 때, 사용해본 경험이 있고 스타벅스 앱이나 거의 대부분의 앱에서 Main 화면으로 사용되는 TabBarController를 먼저 이용하려고 한다.



위의 이미지에서 확인할 수 있는데, 각각의 Tab은 각각의 view controller를 가지고 있다.
주로 NavigationController과 함께 사용되며, 한 tab의 view controller에서 세부적으로 들어가거나 뒤로가기 버튼 등을 이용하게 된다.
NavigationController에 대해 간략하게 알아보자면, push-pop과 present-dismiss 방식이 있다.



push-pop 방식은 view가 완전히 바뀌게 되고, stack 형태로 view가 쌓이게 된다.
뒤로가기 버튼이나 좌-우 슬라이드를 통해 이전 뷰로 돌아갈 수 있다.
present-dismiss 방식은 부모의 view에 팝업 형식으로 아래에서 위로 새로운 view가 나타나게 되고, 위에서 아래로 화면을 쓸어 내리면서 본래의 view로 돌아갈 수 있다.

UIKit에서 구현 방법을 간략하게 확인해보자.

push - pop

@objc func pushTapped(sender: UIButton) {
    navigationController?.pushViewController(PushViewController(), animated: true)
}

@objc func popTapped(sender: UIButton) {
    navigationController?.popViewController(animated: true)
}

present - dismiss

@objc func presentTapped(sender: UIButton) {
    navigationController?.present(PresentViewController(), animated: true, completion: nil)
}

@objc func dismissTapped(sender: UIButton) {
    dismiss(animated: true, completion: nil)
}




다시 본론으로 돌아가, TabBarController를 구현해보았다. 우선 하단의 tab bar 버튼에 들어갈 이미지 등을 설정하기 위한 함수가 필요하여 세팅 과정이 먼저 필요하다.

UIViewController+Utils.swift

import UIKit

extension UIViewController {
    func setStatusBar() {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithTransparentBackground() // to hide Navigation Bar Line also
        navBarAppearance.backgroundColor = appColor
        UINavigationBar.appearance().standardAppearance = navBarAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
    }
    
    func setTabBarImage(imageName: String, title: String) {
        let configuration = UIImage.SymbolConfiguration(scale: .large)
        let image = UIImage(systemName: imageName, withConfiguration: configuration)
        tabBarItem = UITabBarItem(title: title, image: image, tag: 0)
    }
}

iOS 13에서 업데이트된 UINavigationBarAppearnace를 이용한다. 이는 tab bar가 아닌, 가장 상단 노치 쪽에 나타나는 부분이다. configureWithTransparentBackground 메소드를 사용하였는데, 이는 bar appearance객체를 transparent background와 shadow가 없게 configure한다 라는 뜻이다. 이전에 storyboard 방식으로 navbar의 배경색을 설정할 때, 노치 화면쪽 시간이 뜨는 부분과 배터리나 통신 상태가 나타나는 부분에는 컬러가 지정이 안되었던 경험이 있는데, 이를 이용하면 전체적으로 백그라운드 색이 바뀌게 된다!

appColor는 AppDelegate에서 global하게 .systemTeal로 설정을 해주었고, scrollEdgeAppearance와 standardAppearance을 설정해주었다. iOS15 이후, Navbar가 확장되어 scrollEdgeAppearance는 기본적으로 투명한 배경으로 생성이 되어 컨텐츠가 없는 경우 기본적으로 투명한 배경색으로 보이게끔 변하였다. 그리하여 배경을 가진 이전 bar는 사라지고 콘텐츠를 스크롤 하는 경우에 다시 bar가 보이게 된다. UINavigationBarAppearance를 이용하여 이러한 시각적인 문제를 해결할 수 있고, standardAppearance와 scrollEdgeAppearance를 동일하게 설정해야 한다.

다음은 setTabBarImage 인데, 이 부분에서 imageName과 title을 받아 tab bar의 이미지와 이름을 설정하게 된다.

MainViewController.swift

import UIKit

class MainViewController: UITabBarController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        setupTabBar()
    }
    
    private func setupViews() {
        let summaryVC = AccountSummaryViewConroller()
        let moneyVC = MoveMoneyViewController()
        let moreVC = MoreViewController()
        
        summaryVC.setTabBarImage(imageName: "list.dash.header.rectangle", title: "Summary")
        moneyVC.setTabBarImage(imageName: "arrow.left.arrow.right", title: "Money")
        moreVC.setTabBarImage(imageName: "ellipsis.circle", title: "More")
        
        let summaryNC = UINavigationController(rootViewController: summaryVC)
        let moneyNC = UINavigationController(rootViewController: moneyVC)
        let moreNC = UINavigationController(rootViewController: moreVC)
        
        summaryNC.navigationBar.barTintColor = appColor
        hideNavigationBarLine(summaryNC.navigationBar)
        
        let tabBarList = [summaryNC, moneyNC, moreNC]
        
        viewControllers = tabBarList
    }
    
    // to disappear 1pt line
    private func hideNavigationBarLine(_ navigationBar: UINavigationBar) {
        let img = UIImage()
        navigationBar.shadowImage = img
        navigationBar.setBackgroundImage(img, for: .default)
        navigationBar.isTranslucent = false
    }
    
    private func setupTabBar() {
        tabBar.tintColor = appColor
        tabBar.isTranslucent = false
    }
}

class AccountSummaryViewConroller: UIViewController {
    override func viewDidLoad() {
        view.backgroundColor = .systemGreen
    }
}

class MoveMoneyViewController: UIViewController {
    override func viewDidLoad() {
        view.backgroundColor = .systemOrange
    }
}

class MoreViewController: UIViewController {
    override func viewDidLoad() {
        view.backgroundColor = .systemPurple
    }
}

총 3개의 tab bar를 생성하였고, 이미지와 title을 달아주었다. 그리고 각각의 NavigationController를 지정해 주었다. hideNavigationBarLine을 생성해주었는데, 기본적으로 이렇게 NavigationBar를 생성하면 1포인트로 선이 생기는데, 이를 가려주기 위한 것이다. ViewController는 우선 아무런 기능을 하지 않는 색상만 바뀌도록 dummy로 구성을 하였다.


추가적으로 AppDelegate에서 해당 TabBarController를 추가하며 Default index를 지정해줬다.

mainViewController.selectedIndex = 1


위와 같은 방식으로 지정하게 되고, 앱을 켰을 때 0이 제일 첫번째, 1이 두번째, 2가 세번째 화면이 default로 나타나게 된다.



UIKit을 공부하면 할 수록, 협업에서는 당연히 매우 편리하다고 느끼게 되었고 혼자서 개발을 하더라도 storyboard에서 찾으면서 하는 것 보다 가독성이 높은 코드로 바로바로 확인을 하고 수정을 할 때에도 바로바로 확인을 하여 고칠 수 있다는 장점을 느끼게 되었다.

이미지 출처 : https://github.com/jrasmusson/ios-professional-course/tree/main/Bankey/4-Container-ViewControllers

태그:

카테고리:

업데이트: