Wireframe

AppKit의 스크롤뷰, NSScrollView 사용법

iOS에서 화면에 표시할 수 있는 뷰 영역보다 큰 콘텐츠를 표시하기 위해서는 UIScrollView를 사용해서 스크롤 및 확대/축소에 대한 지원을 손쉽게 구현할 수 있음을 우리는 알고 있다. 그렇다면 macOS 환경에서 스크롤뷰는 어떤식으로 구현될 수 있고, 또 그만큼 손쉽게 사용할 수 있을까? 비슷한 스크롤 서비스를 제공한다는 공통점에도 불구하고 데스크톱 환경은 우리가 생각하는 것보다 훨씬 더 복잡하고 많은 요소가 관계하고 있으며 따라서 데스크톱 환경에서의 스크롤은 쉽지 않을지 모른다. 이번 포스팅에서는 AppKit에서 제공하는 스크롤 뷰인 NSScrollView에 대해 알아보자

iOS와 macOS의 차이점

iOS에서 큰 면적의 콘텐츠의 일부를 스크롤 하여 표시하는 기능은 UIScrollView를 통해서 구현한다. UIScrollView는 단일 클래스로 스크롤 서비스를 제공하며, 확대축소를 위해서 델리게이트를 요구하는 것 외에는 간단한 속성값 설정만으로 사용이 가능하며, 스크롤 동작에 필요한 거의 모든  UI구성 요소를 내장하고 있다.
반면 macOS에서는 스크롤 서비스를 구현하는 클래스로 NSScrollView가 있다.  AppKit과 UIKit의 UI 컴포넌트들이 단순히 접두어만 다른 것이 아니라 내부 구현에 차이가 많은 것은 사실이지만, 그 중에서도 스크롤 뷰는 두 플랫폼 간의 차이가 제법 큰 편이다.  일단 NSScrollView에 의한 스크롤 기능 지원은 어떻게 이루어지는지 알아보자

macOS의 스크롤 뷰 구성 요소

macOS의 스크롤 서비스는 NSScrollView에 의해서 제공되며, 이 클래스는 스크롤을 구현하기 위해 필요한 구성요소들을 한 데 결합해주는 중심 역할을 한다. macOS에서의 스크롤 영역과 관련된 각 세부 기능은 다음과 같이 정리할 수 있다.

전통적인 아쿠아 UI로부터 macOS의 UI 디자인이 대대적으로 개편되면서 특히 스크롤러 같은 경우에는 별도의 뷰로 표시되기 보다는 스크롤 뷰 내부에 필요한 경우에만 오버레이되었다가 사라지는 식으로 제공되고 있고, 최근의 UI에서는 눈금자를 쓰는 경우도 거의 존재하지 않는다.
따라서 macOS에서 스크롤 뷰를 쓰기 위해 준비해야하는 설치 절차는 생각보다 더 간단하다.

  1. 도큐멘트 뷰가 될 뷰를 준비한다.
  2. 표시 영역에 맞게 스크롤 뷰를 생성해둔다.
  3. 스크롤뷰의 documentView를 준비한 뷰로 설정한다.
  4. 스크롤뷰를 부모 뷰에 붙인다.

다음은 번들 내 이미지 파일로 스크롤바에 이미지 뷰를 넣는 과정을 기술한 코드이다. 생각보다 매우 간단하다.

var imageView: NSImageView?
var scrollView: NSScrollView?
override function viewDidLoad() {
  super.viewDidLoad()
  // 이미지를 준비하고, 이미지로부터 이미지 뷰를 만든다.
  // 이미지뷰는 이미지의 크기를 따라가지 않으므로 수동으로 지정한다.
  if let image = NSImage("image.jpg") {
    imageView = NSImageView(image: image)
    imageView.frame.size = image.size
  }
  // 스크롤뷰는 부모뷰의 크기와 동일하게 설정한다.
  scrollView = NSScrollView(frame: view.frame)
  scrollView?.documentView = imageView
  view.addSubView(scrollView!)
  // scrollView?.documentView = imageView
}

NSScrollView에 프레임 속성을 주어 표시될 크기를 지정하고 documentView를 설정하면 스크롤 뷰는 자동으로 NSClipView 객체를 하나 만들어서 documentView를 감싸게 한다. (이 클립뷰는 NSScrollViewcontentView 속성으로 참조된다.) 따라서 전체 콘텐츠 중에 실제 화면에 노출될 부분을 잘라서 표시하는 것은 내부의 NSClipView에 의해서 구현된다.

UIScrollView와 차이점

UIScrollViewNSScrollView의 차이는 iOS의 스크롤뷰는 단일 클래스에 의해서 제공되지만, macOS의 스크롤뷰는 실제로는 여러 클래스들이 동원된다는데 차이가 있다.   macOS의 스크롤뷰는 룰러나 스크롤러 같은 부속이 필요하다는 점 때문에 이런 식으로 구성되었으며, iOS의 스크롤뷰는 (iOS는 애초에 스크롤러가 동적으로 오버레이되는 식으로 제어되므로) 스크롤러에 대한 제어를 UIKit이 자동으로 처리할 수 있으며, 별도의 룰러를 필요로 하지도 않으므로 간단하게 구성되었을 것이다.

콘텐츠의 확대와 축소

콘텐츠의 확대/축소는 magnification 값을 조정하여 변경할 수 있다.  단, 이 값을 변경하는 것이 iOS처럼 자동으로 줌인/줌아웃 효과를 주지는 않는다. 이 값을 조정하려면 해당 객체의 animator를 사용해야 한다.

보너스 : 뷰의 애니메이터

macOS 10.5 이상에서 NSView는 NSAnimatablePropertyContainer 프로토콜을 따르고 있고, 따라서 animator() 메소드를 이용해서 애니메이션을 위한 프록시 객체를 얻을 수 있다. 이 프록시에 대해서 키-밸류 코딩 기반의 프로퍼티 변경 메시지를 보내면 애니메이터는 기본 애니메이션 설정값을 이용해서 해당 프로퍼티를 애니메이트할 수 있다.

func zoomOut(_ view: NSScrollView) {
  let m = view.magnification
  view.animator().magnification = m / 2
}

 

Exit mobile version