기어가더라도 제대로
[UIKit-기초] Navigation 상단바 영역 다루기, color navigation bar, change back button, color back button, color navigation title(UINavigationBar, StatusBar, when scrolling, transparent navigation bar) 본문
[UIKit-기초] Navigation 상단바 영역 다루기, color navigation bar, change back button, color back button, color navigation title(UINavigationBar, StatusBar, when scrolling, transparent navigation bar)
Damagucci-juice 2025. 2. 2. 17:42UIKit도 나온지 10년이 넘었고, 스택오버플로우도 거의 object-c가 혼재하던 시절에 나온 코드 자료가 많아서, 한번 정리를 해놓으려 함
편의상 sceneDelegate나 View Controller에서 하지만, Appearance를 편집하는 매니저에서 바꾸는 것을 추천함
- 그 이유는 나중에 뷰컨이 많아지면 어느 뷰컨에서 어떻게 설정을 바꿨는지 알기가 어려워서, 효과들이 중첩되는데 이거가 한번 꼬이면 어느 뷰에서 어떻게 바꿨는지 찾는게 더 오래걸림
사전 설정
- SnapKit: Auto layout을 편하게 하기 위해 사용
- Then: UI 선언을 편하게 하기 위해 사용
- 코드 베이스 UI: 스토리 보드를 사용하지 않을 것임
- FirstViewController와 SecondViewController를 생성하고 각각 배경색과 버튼, 레이블 같은것을 추가함
import UIKit
import Then
import SnapKit
class FirstViewController: UIViewController {
let button = UIButton().then {
$0.setTitle("FirstViewController then move to Second", for: .normal)
$0.setTitleColor(.blue, for: .normal)
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(button)
button.snp.makeConstraints { make in
make.center.equalToSuperview()
}
button.addTarget(
self,
action: #selector(moveToSecondTapped),
for: .touchUpInside
)
}
@objc func moveToSecondTapped() {
print("tapped")
}
}
class SecondViewController: UIViewController {
let label = UILabel().then {
$0.text = "Second View Controller"
$0.textColor = .black
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(label)
label.snp.makeConstraints { make in
make.center.equalToSuperview()
}
}
}
전역적으로 네비게이션 배경색을 변경하기
- SceneDelegate에서 네비게이션 영역을 편집
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// init windows
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
let navigationController = UINavigationController(rootViewController: FirstViewController())
// navigation appearance
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .systemBrown
// set values
navigationController.navigationBar.standardAppearance = appearance
navigationController.navigationBar.compactAppearance = appearance
navigationController.navigationBar.scrollEdgeAppearance = appearance
// activate window with root view controller
window.rootViewController = navigationController
self.window = window
self.window?.makeKeyAndVisible()
}
특정 View Controller에서 Navigation Bar 영역을 편집하기
- SceneDelegate의 Scene 함수에서 Navigation Appearance를 조작하던 곳을 주석 처리
// chanage globally
/*
// navigation appearance
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .systemBrown
// set values
navigationController.navigationBar.standardAppearance = appearance
navigationController.navigationBar.compactAppearance = appearance
navigationController.navigationBar.scrollEdgeAppearance = appearance
*/
- FirstViewController에서 네비게이션 영역 색상을 초록색으로 변경
- 전역적으로 변경하는 것과 달리 국지적으로 변경하는 것은 꼭 리셋을 해주는게 나중에 편함
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// set naivigation background color
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .systemGreen
if let navigationBar = navigationController?.navigationBar {
navigationBar.standardAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// reset naivigation background color
if let navigationBar = navigationController?.navigationBar {
navigationBar.standardAppearance = .init()
navigationBar.compactAppearance = nil
navigationBar.scrollEdgeAppearance = nil
}
}
- 버튼에 다음 뷰컨트롤러로 넘어가는 액션을 추가
// view did load
button.addTarget(
self,
action: #selector(moveToSecondTapped),
for: .touchUpInside
)
@objc func moveToSecondTapped() {
navigationController?.pushViewController(SecondViewController(), animated: false)
}
- 구현 모습
타이틀 색상 변경하기
- 위 gif에서 배경이 초록인데 타이틀 색상이 검정이라 이쁘지 않음, 흰색으로 색칠하기
// FirstViewController.viewWillAppear(animated:)
// change background color
appearance.backgroundColor = .systemGreen
// change title color
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
상단바 영역 투명하게 하기
- SecondViewController에서 화면 상단에 200 높이 짜리 컬러뷰 선언
class SecondViewController: UIViewController {
let colorView = UIView().then {
$0.backgroundColor = .systemGray
}
let label = UILabel().then {
$0.text = "Second View Controller"
$0.textColor = .black
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "Second View Controller"
// setup button
view.addSubview(label)
label.snp.makeConstraints { make in
make.center.equalToSuperview()
}
// setup color view
view.addSubview(colorView)
colorView.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.height.equalTo(200)
}
}
- Appearance 투명하게 설정
// MARK: - SecondViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appearance = UINavigationBarAppearance()
// set navigation transparent background
appearance.configureWithTransparentBackground()
// change title color
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
// set values
if let navigationBar = navigationController?.navigationBar {
navigationBar.standardAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
}
}
- 근데 backbutton이 마음에 안듬, 색상이 매치가 안됨, backbutton 색상도 바꾸기
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appearance = UINavigationBarAppearance()
// set navigation transparent background
appearance.configureWithTransparentBackground()
// change title color
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
// change back button appearance
let buttonAppearance = UIBarButtonItemAppearance(style: .plain)
/// backbutton title color
buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.buttonAppearance = buttonAppearance
/// backbutton tint color
let image = UIImage(systemName: "chevron.backward")?.withTintColor(.white, renderingMode: .alwaysOriginal)
appearance.setBackIndicatorImage(image, transitionMaskImage: image)
// set values
if let navigationBar = navigationController?.navigationBar {
navigationBar.standardAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
}
}
상단 바 영역을 투명하게 하다가 스크롤을 하면 불투명하게 바꾸기
- 스크롤뷰 + 컨텐츠 스택뷰를 생성
class SecondViewController: UIViewController {
let scrollView = UIScrollView()
let contentStackView = UIStackView().then {
$0.axis = .vertical
$0.distribution = .fill
$0.alignment = .fill
$0.spacing = 20
}
let colors = [UIColor.systemBlue, UIColor.systemOrange, UIColor.systemGreen, UIColor.systemRed]
- 스크롤뷰, 스택뷰 레이아웃 잡기
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "Second View Controller"
// setup scroll view
view.addSubview(scrollView)
scrollView.addSubview(contentStackView)
scrollView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
/// 스크롤 뷰를 상단 영역까지 꽉 채우기
scrollView.contentInsetAdjustmentBehavior = .never
// setup contentStackView
contentStackView.snp.makeConstraints { make in
make.edges.width.equalToSuperview()
}
colors.forEach { color in
let coloredView = UIView().then {
$0.heightAnchor.constraint(equalToConstant: 500).isActive = true
$0.backgroundColor = color
}
contentStackView.addArrangedSubview(coloredView)
}
}
- 일반 Appearacne와 스크롤 중일 때 Appearance를 별도로 설정
// MARK: - transparent
let transparentAppearance = UINavigationBarAppearance()
transparentAppearance.configureWithTransparentBackground()
// title color
transparentAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
// button title color
let buttonAppearance = UIBarButtonItemAppearance(style: .plain)
buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white]
transparentAppearance.buttonAppearance = buttonAppearance
// button tint color
let image = UIImage(systemName: "chevron.backward")?.withTintColor(.white, renderingMode: .alwaysOriginal)
transparentAppearance.setBackIndicatorImage(image, transitionMaskImage: image)
// MARK: - opaque
let opaqueAppearance = UINavigationBarAppearance()
opaqueAppearance.configureWithOpaqueBackground()
// title color
opaqueAppearance.titleTextAttributes = [.foregroundColor: UIColor.label]
// button title color
let scrollButtonAppearance = UIBarButtonItemAppearance(style: .plain)
scrollButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.black]
opaqueAppearance.buttonAppearance = scrollButtonAppearance
// button tint color
let scrollBackbuttonImage = UIImage(systemName: "chevron.backward")?.withTintColor(.label, renderingMode: .alwaysOriginal)
opaqueAppearance.setBackIndicatorImage(scrollBackbuttonImage, transitionMaskImage: scrollBackbuttonImage)
- 최상단일 때 투명, 스크롤 중일 때 불투명하게 옵션 설정
// MARK: - SecondViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 생략 ~~
// set values
if let navigationBar = navigationController?.navigationBar {
// set opaque type when top edge
navigationBar.scrollEdgeAppearance = transparentAppearance
// set transparent type when scrolling
navigationBar.standardAppearance = opaqueAppearance
}
}
- 완성 화면
전체 코드
https://github.com/Damagucci-Juice/ColoringNavigationArea
GitHub - Damagucci-Juice/ColoringNavigationArea
Contribute to Damagucci-Juice/ColoringNavigationArea development by creating an account on GitHub.
github.com
참조
- 백버튼 이미지 변경: https://sarunw.com/posts/how-to-change-back-button-image/
How to change a back button image | Sarunw
Learn how to change a UINavigationBar back button indicator.
sarunw.com
- 상단 영역 색칠: https://nemecek.be/blog/150/customizing-the-navigation-bar-in-uikit
Customizing the navigation bar in UIKit
What worked for me and what didn’t.
nemecek.be
- 백버튼 이미지 색상 변경, "OlegKorchitskiy" 답변: https://developer.apple.com/forums/thread/709517
NavigationBar Back Button Color iO… | Apple Developer Forums
I just noticed, that iOS 16 is using the accent color for the navigation bar back button. (SwiftUI) When running my app on iOS 15 devices it's white. Is there a way to change that behavior? I want to have another accent color than white.
developer.apple.com
'UIKit 기초' 카테고리의 다른 글
[UIKit-응용] Tab 전환을 모달로 하기(UITabBarController, Modal, Sheet) (0) | 2025.02.04 |
---|---|
[UIKit-기초] UISegmentedControl - basic (0) | 2025.02.03 |
[UIKit-기초] Builder 패턴 사용해보기 (0) | 2025.01.31 |
[UIKit-기초] UIStoryboard의 화면 전환(Segue) (0) | 2025.01.27 |
[UIKit-기초] Xib에서 코드로 UIView 파일을 불러오기 (0) | 2025.01.26 |