[소소한 개발 일지] SwiftUI 기반 macOS 애플리케이션의 타이틀바 영역에 커스텀 뷰 추가하기

Explanation

오늘은 간단하게 SwiftUI를 사용하는 MacOS 애플리케이션 윈도우의 툴바 영역(타이틀바 영역)에 커스텀 뷰를 추가하는 방법에 대하여 적어보려합니다.

이 글에 사용되는 샘플 코드들은 아래의 리포지토리에서 모두 확인 하실 수 있습니다.
링크: https://github.com/falsy/blog-post-example/tree/main/macOS-project/toolbarView

전 아직 조금씩 공부하고 있는 단계라, 글 내용에 잘못 설명된 부분이 있을 수 있습니다!!

1. SwiftUI – toolbar

SwiftUI에서 툴바 영역은 toolbar라는 뷰 빌더 메서드를 사용해서 커스텀할 수 있는데요.

하지만, 이 toolbar 영역을 구성할 수 있는 뷰는 제한적인데요. 일반적으로 툴바 영역 내부에는 버튼을 사용하고, 버튼의 위치를 제어하는 정도의 기능만 제공하는 거 같아요.

아마도 SwiftUI의 다양한 OS를 모두 지원하는 특징 때문에 AppKit에 비해서 제공되는 기능이 제한적이고, 또 아무래도 iOS의 시장이 크다보니 우선 iOS 중심으로 만들고 있어서 더 그렇지 않을까 싶어요.

VStack이나 HStack처럼 뷰 요소를 추가할 수도 있긴한데, 결정적으로 “.frame(maxWidth: .infinity, maxHeight: .infinity)” 처럼 뭐라고 표현해야 할까요.. 음.. 윈도우 크기에 따른 꽉찬 영역을 설정할 수 없습니다. 그리고 그 밖에도 기대한 것과 다르게 동작하는 경우가 많습니다!

저는 그래서 이전까지 전체 너비를 GeometryReader를 사용해서 윈도우 사이즈가 변경될 때마다 뷰 영역의 너비 값을 직접 변경해 주는 식으로 구현했답니다.. 이마저도 macOS v14까지는 괜찮았는데, v15부터는 약간 생각과 다르게 동작하는 부분이 많아서 수정이 필요했습니다.

2. NSTitlebarAccessoryViewController

이제 구현 방법에 대해 이야기해 보자면, 일단 SwiftUI만으로는 구현할 수 있는 방법은 아직 방법이 없는 것 같았고 AppKit을 사용해서 구현할 수 있었습니다.
우선 SwiftUI 기본 윈도우를 사용하지 않고 AppDelegate를 사용해서 새 윈도우를 호출해 줍니다.

AppDelegate를 선언하기 앞서 툴바 영역에 사용할 뷰와 뷰 컨트롤러를 먼저 만들어 줄게요.

AppKit에서 제공하는 NSTitlebarAccessoryViewController 클래스를 사용해서 툴바 영역에 커스텀 뷰를 추가할 수 있습니다. 저는 SwiftUI를 사용해서 뷰를 만들고 NSHostingView를 사용해서 뷰를 추가해주었습니다.

이제 마지막으로 AppDelegate에 추가를 해주면!

여기서 중요한 부분은 이 부분입니다.

이렇게 애플리케이션 윈도우의 툴바 영역에 커스텀 뷰를 구현할 수 있답니다.

3. 그밖의..

사소한 팁??을 추가하자면, 아래와 같이 코드를 추가해서 기본 타이틀바 영역을 숨길 수 있고

그리고 위와 같은 기본 구성에서는 왼쪽 상단의 닫기, 최소화, 최대화 버튼과 윈도우와의 여백?이 가까운데요. 아래와 같이 빈 툴바를 추가해주면 간격을 조금 넓혀줄 수 있습니다.

오늘의 포스팅은 NSTitlebarAccessoryViewController 클래스만 알았으면 간단한 구현인데..
저는 이걸 몰라서, 구현하는 데 몇 개월 걸렸다는 사실은 안비밀..