https://developer.apple.com/documentation/appkit/nsscrubber
"A customizable item picker control for the Touch Bar."
터치 바에서 커스터마이징 가능한 아이템 picker 컨트롤입니다.
class NSScrubber : NSView
지원되는 맥북 프로 모델에서 터치 바에 있는 수평 방향 아이템 picker 컨트롤을 제공하기 위해 스크러버(NSScrubber
클래스의 인스턴스)를 사용할 수 있습니다. 사용자가 라이브러리에 있는 사진, 날짜 범위에서 날짜와 같은 관련 컬렉션의 아이템을 집을 수 있도록 해주는 스크러버를 사용하시기 바랍니다.
NSScrubber
클래스를 포함해 NSTouchBar
및 관련 클래스를 사용하는 방법을 설명하고 있는 아래 샘플 코드 프로젝트를 참조하시기 바랍니다.
NSTouchBar Catalog
https://developer.apple.com/documentation/appkit/touch_bar/creating_and_customizing_the_touch_bar
ToolBar Sample
https://developer.apple.com/documentation/appkit/touch_bar/integrating_a_toolbar_and_touch_bar_into_your_app
스크러버에 나타나는 각 아이템은 선택 및 스크러버에 적합한 데코레이션을 지원하는 특수한 뷰입니다. 스크러버는 인덱스 위치에 따라 아이템을 추적합니다.
Note
터치 바 용어 아이템을 이해하도록 주의하시기 바랍니다. 스커러버에 대한 아이템은 스크러버에 있는 특정 인덱스 위치에서의 뷰(구체적으로NSScrubberItemView
인스턴스)입니다. 이는 테이블에 있는 행과 유사합니다. 대조적으로 바(NSTouchBar
클래스의 인스턴스)에 대한 아이템은 뷰를 갖는NSTouchBarItem
인스턴스입니다.
스크러버에는 딜리게이트 프로토콜, 데이터 소스 프로토콜, 콜백 기반 레이아웃 API 등 여러 클래스가 존재합니다. 디자인 패턴은 컬렉션 뷰(NSCollectionView
클래스의 인스턴스)에서 사용되는 디자인 패턴을 연상시킵니다. 배경지식으로 NSCollectionView
오버뷰를 참고하는 것이 도움이 될 것입니다. 차이가 있음도 알아야 합니다. 예를 들어 스크러버와 컬렉션 뷰 모두 makeItemWithIdentifier:
메소드를 사용하고, 재사용 큐를 사용하지만, 스크러버는 NSView
클래스로부터 서브클래싱된 반면 컬렉션 뷰는 NSViewController
클래스로부터 서브클래싱 되었습니다.
스크러버는 아래 항목을 사용합니다.
NSScrubber
클래스의 인스턴스)입니다.NSScrubberDataSource
프로토콜을 따르고 있는) 필요한 즉시 앱에 있는 관련 데이터 컬렉션으로부터 스크러버에 스크러버 아이템을 제공합니다. 스크러버의 dataSource
속성에서 데이터 소스를 구체화해야 합니다.NSScrubberDelegate
프로토콜을 따르고 있습니다.) 이 딜리게이트의 didBeginInteracting(with:)
, didCancelInteracting(with:)
메소드와 같은 사용자 상호작용에 응답하는 것입니다. 스크러버의 딜리게이트 속성에 딜리게이트를 구체화해야 합니다. 스크러버의 강조 및 선택에 응답하도록 딜리게이트를 사용할 수도 있으며, 스크러버에서 아이템이 변경되는 경우 응답하도록 사용할 수도 있습니다.NSScrubberLayout
추상 클래스의 서브클래스 인스턴스입니다. 보통 NSScrubberFlowLayout
구체화 서브클래스입니다.) 시스템으로부터의 호출에 응답하도록 레이아웃을 구현함으로써 스크러버에 나타나는 아이템에 대한 뷰 구체화를 반환하게 됩니다. 이러한 방법으로 레이아웃은 스크러버의 포함된 아이템들을 정렬하고 데코레이팅 하는 것을 도우며, 사용자 상호작용에 응답해 모양의 변경을 제공합니다. 스크러버의 scrubberLayout
속성에서 레이아웃을 구체화합니다.터치 바에서 스크러버를 사용하는 방법을 알아가기 전에 NSTouchBar
클래스의 오버뷰를 읽어두셔야 합니다.
NSTouchBar
https://developer.apple.com/documentation/appkit/nstouchbar
https://velog.io/@panther222128/?q=NSTouchBar
스크러버는 컬렉션 뷰에서 사용하는 것과 유사한 패턴을 사용해 데이터 소스와 딜리게이트를 사용합니다. 아래와 같습니다.
Data source 스크러버에 아이템을 공급하려면 NSScrubberDataSource
프로토콜을 따르는 객체를 구현해야 하고, 스크러버의 dataSource
속성에 해당 객체를 구체화해야 합니다. 두 가지 내장된 아이템 타입이 있으며, NSScrubberTextItemView
와 NSScrubberImageItemView
구체화 클래스에 의해 제공됩니다. 스크러버 아이템에 대한 더 많은 내용은 Scrubber Items를 살펴보시기 바랍니다.
Scrubber Items는 이 글의 아래에 나옵니다.
아래는 스크러버에 의해 표시되는 아이템의 수를 반환하고 있는 numberOfItems
데이터 소스 메소드의 구현 예시입니다.
func numberOfItems(for scrubber: NSScrubber) -> Int {
return self.scrubberItems.count;
}
스크러버 아이템의 개수와 더불어 scrubber(_:viewForItemAt:)
메소드로 개별 아이템을 제공하기 위해 데이터 메소드를 사용해야 합니다. 아래가 구현 예시입니다.
func scrubber(_ scrubber: NSScrubber, viewForItemAt index: Int) -> NSScrubberItemView { let itemView = scrubber.makeItem(withIdentifier: "TextScrubberItemIdentifier", owner: self) as! NSScrubberTextItemView
itemView.title = String(index)
return itemView
}
리소스 사용 및 성능을 최적화하기 위해 스크러버는 NSCollectionView
의 재사용 큐와 유사한 재사용 큐를 사용합니다.
Delegate 사용자 상호작용 응답, 시각화, 강조, 선택 변경을 위해 NSScrubberDelegate
프로토콜을 따르는 딜리게이트 객체를 구현해야 하고, 해당 객체를 스크러버의 딜리게이트 속성에 구체화해야 합니다.
스크러버를 위한 scrubber(_:didSelectItemAt:)
딜리게이트 메소드를 최소한으로 구현한 모습은 아래와 같습니다.
func scrubber(_ scrubber: NSScrubber, didSelectItemAt index: Int) {
// Log the index value for the item the user selected
print("\(#function) at index \(index)")
}
스크러버는 이 섹션에서 설명하는 것처럼 터치 상호작용을 위한 여러 가지 내장된 기능을 제공합니다. 스크러버를 서브클래싱해서 터치 상호작용을 커스터마이징 할 수 있습니다.
스크러버의 터치 상호작용 모델을 구체화하려면 스크러버 속성을 조정하면서 아래에 나오는 값을 설정해야 합니다. mode
, isContinuous
, itemAlignment
입니다. 아래는 이러한 속성에 대한 올바른 선택을 하는 방법을 보여줍니다.
Scrolling or fixed 스크러버가 손가락의 수평 움직임에 따라 스크롤될지 손가락이 움직일 때 한 자리에 고정될지를 결정행야 합니다.
mode
속성에 NSScrubber.Mode.free
값을 구체화해야 합니다.mode
속성(기본값입니다)에 NSScrubber.Mode.fixed
값을 구체화해야 합니다. 이 경우 사용자의 손가락이 스크러버 뷰의 왼쪽 혹은 오른쪽 모서리에 닿고 모서리를 넘어서서 아이템이 있다면, 스크러버는 자동으로 해당 아이템들을 뷰로 가져오기 위해 스크롤합니다.Selection style 의도를 갖는 선택 제스쳐에 대해서만 아이템 선택을 할지 혹은 스크러버에서 손가락이 수평으로 움직이는 동안 연속적으로 아이템 선택을 할지 결정해야 합니다.
isContinuous
속성(기본값입니다)에 NO
값을 구체화해야 합니다. free
(스크롤링) 모드에서 사용자는 아이템을 강조하고 선택하기 위해 탭해야 합니다. fixed
(스크롤링 없는) mode
에서 손가락을 떼어냄으로써 스크러버에 대한 상호작용이 끝나는 것은 가장 최근에 강조된 아이템을 선택하도록 합니다. 그러나 상호작용 시작 전에 이미 강조된 아이템이 있고 사용자가 해당 아이템에 상호작용을 재개(fixed
mode
)하는 경우 사용자의 손가락을 추적하면서 선택은 연속적으로 변경됩니다. isContinuous
속성 값이 NO
여도 이렇게 작동합니다.isContinuous
에 YES
값을 구체화해야 합니다. 그러면 “Position-based Item Selection”에서 설명하는 것처럼 아이템 선택 동작은 mode
와 itemAlignment
속성에 의존하게 됩니다.velog는 코드 작성에서 영어로 센터를 입력하면 자동으로 비공개 게시글이 되어 한글로 센터라고 입력했습니다.
Item alignment 스크러버의 itemAlignment
속성을 설정하는 것은 두 가지에 영향을 미칩니다. 첫 번째는 아이템 강조 및 선택이고, 두 번째는 수동 혹은 자동 스크롤링 이후 스크러버 아이템의 남아있는 위치입니다. 이 속성에 사용 가능한 값은 NSScrubber.Alignment.leading
, NSScrubber.Alignment.센터
, NSScrubber.Alignment.trailing
, NSScrubber.Alignment.none
입니다. 이 상수가 어떻게 작동하는지에 대해서는 NSScrubber.Alignment
열거형을 살펴보시기 바랍니다.
NSScrubber.Alignment
https://developer.apple.com/documentation/appkit/nsscrubber/alignment
https://velog.io/@panther222128/NSScrubber.Alignment
스크러버의 터치 상호작용 모델을 구체화하려면, 스크러버 속성을 조정해서 아래 값을 설정해야 합니다. mode
, isContinuous
, itemAlignment
입니다. 이러한 속성에 대해 값을 올바르게 선택하는 방법이 아래에 있습니다.
Scrolling or fixed 손가락의 수평 움직임을 추적해 스크롤할지 혹은 손가락이 이동할 때 고정된 위치에 남을지 결정해야 합니다.
mode
속성에 NSScrubber.Mode.free
값을 구체화해야 합니다. mode
속성(기본값입니다)에 NSScrubber.Mode.fixed
값을 구체화해야 합니다. 이 경우 사용자의 손가락이 스크러버 뷰의 왼쪽 혹은 오른쪽 모서리에 도달하고 모서리를 넘어서 아이템이 존재하는 경우 스크러버는 자동으로 뷰에 해당 아이템을 가져오기 위해 스크롤합니다.Selection style 의도를 갖는 선택 제스쳐에만 아이템 선택을 할지 혹은 스크러버에서 손가락이 수평으로 이동하는 동안 연속적으로 선택을 할지 결정해야 합니다.
의도를 갖는 선택의 경우 스크러버의 isContinuous
속성(기본값입니다)에 NO
값을 구체화해야 합니다. free
(스크롤링) mode
에서 사용자는 아이템을 강조하고 선택하기 위해 아이템을 탭해야 합니다. fixed
(스크롤이 아닌) mode
에서 손가락을 떼어 스크러버 상호작용을 끝내면 가장 최근에 강조된 아이템을 선택합니다. 그러나 상호작용 시작 전 이미 강조된 아이템이 있고 사용자가 상호작용(fixed
mode
)을 재개하는 경우 사용자의 손가락을 추적하면서 선택은 연속적으로 변경됩니다. isContinuous
속성 값이 NO
여도 이렇게 작동합니다.
연속적 선택의 경우 isContinuous
속성에 YES
값을 구체화해야 합니다. 그러면 아이템 선택 동작은 mode
및 itemAlignment
속성에 의존합니다. Position-based Scrubber Item Selection에서 설명하는 것과 같습니다.
Position-based Scrubber Item Selection은 이 글의 아래에 나옵니다.
velog는 코드 작성에서 영어로 센터를 입력하면 자동으로 비공개 게시글이 되어 한글로 센터라고 입력했습니다.
Item alignment 스크러버의 itemAlignment
속성을 설정하는 것은 두 가지에 영향을 미칩니다. 1) 아이테 강조와 선택입니다. 2) 수동 혹은 자동 스크롤링 이후 스커러버 아이템 위치의 남은 부분입니다. 이 속성에서 사용 가능한 값은 NSScrubber.Alignment.leading
, NSScrubber.Alignment.센터
, NSScrubber.Alignment.trailing
, NSScrubber.Alignment.none
입니다. 이러한 상수가 어떻게 작동하는지는 NSScrubber.Alignment
열거형을 보시기 바랍니다.
NSScrubber.Alignment
https://developer.apple.com/documentation/appkit/nsscrubber/alignment
https://velog.io/@panther222128/NSScrubber.Alignment
앞선 설명에서 scrolling
, selection
, alignment
에 대한 선택은 결합된 형태로 강조 및 선택 동작에 영향을 미칩니다. 강조 및 선택에 대한 세부 내용은 Position-based Scrubber Item Selection을 살펴보시기 바랍니다. 또한, 정렬에 대한 선택은 스크롤 상호작용에 따라오는 스크러버 아이템 남은 부분 위치 동작에 영향을 미칩니다. 남아있는 위치에 대한 자세한 내용은 Scrubber Item Resting Position을 살펴보시기 바랍니다.
두 가지 참고 권장 내용 모두 아래에 나옵니다.
velog는 코드 작성에서 영어로 센터를 입력하면 자동으로 비공개 게시글이 되어 한글로 센터라고 입력했습니다.
연속적 스타일을 갖는 free
모드(mode
속성 값은 NSScrubber.Mode.free
이고, isContinuous
속성 값이 YES
)에서 정렬 축에서의 스크러버 아이템은 자동으로 강조되고 선택됩니다. 정렬 축은 왼쪽, 오른쪽 모서리 혹은 스크러버의 중앙이며, NSScrubber.Alignment
열거형으로부터의 상수를 사용한 itemAlignment
속성의 값 설정에 의해 구체화됩니다.NSScrubber.Alignment.none
의 정렬 축 구체화는 위치 기반 아이템 선택에서 NSScrubber.Alignment.센터
의 값과 동일합니다.
의도를 갖는 선택 스타일을 갖는 free
mode
(mode
속성 값이 NSScrubber.Mode.free
이고, isContinuous
속성 값이 NO
)에서 시스템은 아이템 선택에 관해 itemAlignment
속성 값을 무시합니다.
fixed
mode
(mode
속성 값이 NSScrubber.Mode.fixed
)에서 시스템은 아이템 선택에 관해 itemAlignment
속성 값을 무시합니다. isContinuous
속성에 구체화한 값과 상관이 없습니다.
itemAlignment
속성에서 제공한 값은 수동 혹은 자동 스크롤링을 따르는 자동 스크러버 아이템 남은 위치를 구체화합니다. (또한, Choosing a Scrubber Touch-Interaction Model에서 설명한 것처럼 이 값은 아이템 강조와 선택에 영향을 미칩니다.) 시스템은 직접 구체화한 남은 위치 설정의 뜻에 따르고, mode
및 isContinuous
값은 무시합니다.
구체적으로 아래와 같습니다.
velog는 코드 작성에서 영어로 센터를 입력하면 자동으로 비공개 게시글이 되어 한글로 센터라고 입력했습니다.
이 섹션에서 설명하는 것처럼 스크러버는 두 가지 클래스의 도움에 따라 아이템을 위해 뷰를 설정합니다. NSScrubberLayout
, NSScrubberLayoutAttributes
가 두 가지 클래스입니다.
레이아웃은 NSScrubberLayout
추상 클래스의 구체화된 구현입니다. AppKit
은 사전에 설정된 레이아웃 구체화 서브클래스 두 가지를 제공합니다. NSScrubberFlowLayout
, NSScrubberProportionalLayout
이 두 가지입니다. 만약 이러한 내장된 레이아웃 타입을 사용한다면, 스크러버의 scrubberLayout
속성에 내장된 레이아웃 선택을 추가하는 것을 제외하고 추가적으로 레이아웃 코드를 작성할 필요는 없습니다. 아래 스위프트 예시는 플로 레이아웃에서 간단한 단계를 보여주고 있습니다.
Listing 1 Adding a built-in layout to a scrubber
myInformationScrubber.scrubberLayout = NSScrubberFlowLayout()
커스텀 레이아웃을 생성하려면, NSScrubberLayout
클래스를 서브클래싱하고, 이 클래스의 콜백 메소드를 구현해야 합니다. 뷰를 즉각적으로 제공해주는 뷰 딜리게이트(테이블 뷰에서 사용되는 것과 같은)와 다르게 스크러버 레이아웃 콜백은 즉각적으로 뷰의 구체적 사항을 제공합니다. 이 콜백을 사용해서 아래를 구체화해야 할 것입니다.
커스텀 스크러버 생성 시 시각적 차원 전체를 구체화해야 합니다. init(frame:)
, init(coder:)
이니셜라이저를 사용하거나 인터페이스 빌더를 사용해서 구체화합니다.
커스텀 스크러버에서 요소에 대한 전체 넓이 및 높이를 반환해야 합니다. 현재로써 시각화되지 않는 것도 포함하며, 레이아웃에서 scrubberContentSize
를 사용해 구현합니다. 포인트 단위로 높이 및 넓이를 구체화해야 합니다. 표준 높이를 사용하려면 값을 30으로 구체화해야 합니다.
NSScrubberLayoutAttributes
클래스의 인스턴스를 반환하는, 두 가지 요구되는 콜백 메소드를 사용하면서 구체화합니다. 시스템은 필요한 경우 사용자가 레이아웃의 소유하고 있는 스크러버와 상호작용할 때 하나 혹은 다른 메소드를 호출할 것입니다.Table 1 Layout attribute callbacks
Callback method | How to use |
---|---|
layoutAttributesForItem(at:) | 메소드 호출에서 시스템에 의해 요청되는 인덱스 위치의 한 스크러버 아이템에 뷰 특성 값을 구체화하는 NSScrubberLayoutAttributes 인스턴스를 반환해야 합니다. |
layoutAttributesForItems(in:) | 메소드 호출에서 시스템에 의해 요청되는 시각적 사각형 내부의 아이템에 아이템 뷰 특성들 하나마다 구체화하는 NSScrubberLayoutAttributes 인스턴스의 집합을 함께 반환합니다. |
명시적으로 레이아웃을 무효화할 수 있습니다. invalidateLayout()
메소드를 호출함으로써 무효화할 수 있습니다. 앱이 레이아웃 업데이트를 요구하는 방법에서 스크러버의 정보를 변경시킬 때마다 이를 수행하시기 바랍니다. 예를 들어 하나 혹은 하나 이상의 아이템에 보여지는 텍스트를 변경하려고 한다면, 레이아웃을 무효화해야 합니다.
조건 하에서 레이아웃 생명주기를 구체화할 수 있습니다. 사용자가 레이아웃의 스크러버에서 다른 무엇을 선택하는 경우처럼 레이아웃은 자동으로 무효화되어야 하는 경우입니다. 자동 무효화 API는 아래 두 속성과 하나의 메소드로 구성됩니다.
shouldInvalidateLayoutForSelectionChange
shouldInvalidateLayoutForHighlightChange
shouldInvalidateLayoutForChange(fromVisibleRect:toVisibleRect:)
예를 들어 어떤 아이템이 사용제 의해 선택되었는지에 의존하는 스커러버 레이아웃 특징을 디자인하려면, 스크러버의 shouldInvalidateLayoutForSelectionChange
메소드로부터 YES
값을 반환해야 합니다. 레이아웃 특성 객체는 단일 아이템에 대해 뷰를 설명하고자 설정하는 NSScrubberLayoutAttributes
클래스의 인스턴스입니다. 클래스는 아래에 보이는 내장된 특성을 제공합니다.
itemIndex
—스크러버 내부에서 아이템의 인덱스 위치입니다.frame
—아이템의 프레임 사각형입니다.alpha
—아이템의 투명도입니다.NSScrubberLayoutAttributes
클래스를 서브클래싱함으로써 추가적인 아이템 특성을 구체화할 수 있습니다. 예를 들어 기하학적 변형 특성을 구체화할 수 있습니다.
커스텀 NSScrubberLayout
서브클래스를 사용하는 경우 캐싱된 데이터를 버리는 것처럼 모든 커스텀 레이아웃 상태를 지우기 위해 invalidateLayout()
메소드를 위한 구현을 제공합니다.
레이아웃 무효화(Layout Implementation에서 설명한)의 이면은 리드로잉에 대한 준비입니다. 이는 레이아웃의 prepare()
메소드를 수행합니다. 레이아웃 준비의 목적은 성능 최적화입니다. 스크러버는 무효화와 리드로잉 사이에서 정확히 한 번 prepare()
메소드를 호출합니다. 리드로잉 전, 이 단계에서 할 수 있는 한 one-time, up-front 작업을 완료하시기 바랍니다.
prepare()
메소드 반환 후 시스템은 세 가지 NSScrubberLayout
메소드를 반복해서 호출하는 것과 함께 스크러버 뷰 계층구조를 업데이트합니다. layoutAttributesForItem(at:)
, layoutAttributesForItems(in:)
, scrubberContentSize
가 세 가지입니다. 레이아웃 준비 동안 했었던 작업의 이점을 활용하면서 가능한 빠르게 반환 값을 제공하기 위해 이 메소드들을 구현하시기 바랍니다.
스크러버 아이템을 나타내는 뷰는 scrubber(_:viewForItemAt:)
메소드를 사용해서 데이터 소스 객체에 의해 제공됩니다. AppKit
은 목적이 내장된 사용 가능한 두 가지 뷰 클래스를 제공하며, 모두 추상 NSScrubberItemView
클래스의 구체화 서브클래스입니다.
NSScrubberImageItemView
는 image
, imageView
, imageAlignment
속성을 갖습니다.NSScrubberTextItemView
는 textField
와 title
속성을 갖습니다.커스텀 아이템을 생성하려면 이러한 것들을 서브클래싱하거나 추상 슈퍼클래스, NSScrubberItemView
를 서브클래싱하시기 바랍니다.
스크러버를 보여주려면 스크러버를 NSTouchBar
객체(커스텀 아이템 혹은 팝오버 아이템으로써 바에 추가하는)에 연결시켜야 하고, 바를 앱에 있는 적합한 리스폰더 객체에 연결시켜야 합니다. 그러면 시스템은 적합한 시점에 터치 바에서 스크러버만을 보여줍니다. 바 및 리스폰더 체인에 대한 더 많은 정보는 NSTouchBar
에서 오버뷰를 보시기 바랍니다.
NSTouchBar
https://developer.apple.com/documentation/appkit/nstouchbar
https://velog.io/@panther222128/?q=NSTouchBar
스크러버와 스크롤 뷰 사이에서 선택하는 경우 컨텐트의 양 혹은 컨텐트 자체가 스크러버에서 작동이 어렵지 않는 한 스크러버를 사용하시기 바랍니다. 스크러버 상호작용은 터치 바에 최적화되어 있으며, 캘린더에서의 날짜처럼 사용자가 몇 가지 선택을 직접 할 수 있도록 해주기 위한 더 나은 옵션을 줍니다.