Background
API
기본적으로 지원하긴 하는데, 잘 보이려면 몇가지를 고려해야 한다.
아이콘으로 PDF 이미지를 쓰고 있다면 Preserve Vector Data 옵션에 체크
레스터라이징 된 이미지라면, 큰 버전을 API로 제공하는 방법이 있다.
// UIBarItem
var largeContentSizeImage: UIImage?
open var largeContentSizeImageInsents: UIEdgeInsets
커스텀 UI
iOS 13 이전에는 기본적으로 알아서 처음부터 만들어야 했다.
13부터 표준 UIKit과 동일한 형태로 지원할 수 있는 API를 제공한다.
UILargeContentViewerItem 프로토콜
public protocol UILargeContentViewerItem: NSObjectProtocol {
// Large Content Viewer를 통해서 해당 뷰를 보여줄 지 여부
var showsLargeContentViewer: Bool { get }
var largeContentTitle: String? { get }
var largeContentImage: UIImage? { get }
// 원래의 작은 이미지를 스케일해서 사용할 것인지 여부
// PDF + Preserve Vector Data 일때 true로 해놓으면 됨.
var scalesLargeContentImage: Bool { get }
var largeContentImageInsets: UIEdgeInsets { get }
}
UIView가 위 프로토콜을 구현하고, setter를 제공하기 떄문에 서브클래싱할 필요 없이 설정할 수 있다.
extension UIView {
var showsLargeContentViewer: Bool
var largeContentTitle: String?
var largeContentImage: UIImage?
var scalesLargeContentImage: Bool
var largeContentImageInsets: UIEdgeInsets
}
UIButton, UILabel등은 타이틀과 이미지의 기본값을 제공하기도 한다.
탭뷰 자체에 인터렉션을 추가해야 하는데, 이는 UIInteraction을 추가함으로써 이뤄진다.
extension UIView {
func addInteraction(_ interaction: UIInteraction)
}
Large Content Viewer를 쓰기위한 Interaction
class UILargeContentViewerInteraction: NSObject, UIInteraction {
init(delegate: UILargeContentViewerInteractionDelegate?)
weak var delegate: UILargeContentViewerInteractionDelegate? { get }
var gestureRecognizerForExclusionRelationship: UIGestureRecognizer { get }
class var isEnabled: Bool { get }
}
extension UILargeContentViewerInteraction {
class let enabledStatusDidChangeNotification: NSNotification.Name
}
protocol UILargeContentViewerInteractionDelegate: NSObjectProtocol {
// 사용자가 마지막으로 손을 뗐을 때 호출
// 이를 구현하지 않고, 표준 UIKit 컨트롤을 쓰면 touchUpInside 이벤트가 날아간다.
optional func largeContentViewerInteraction(_ interaction: UILargeContentViewerInteraction,
didEndOn item: UILargeContentViewerItem?,
at point: CGPoint)
// 특정 포인트에 대한 아이템을 반환
// 제공하지 않을 경우 뷰 계층을 재귀적으로 뒤져서 찾아냄
// 뷰를 사용하지 않는 경우에서 유용
optional func largeContentViewerInteraction(_ interaction: UILargeContentViewerInteraction,
itemAt point: CGPoint) -> UILargeContentViewerItem?
// Large Content Viewer를 담을 ViewController
// 기본적으로 해당 인터렉션이 추가된 뷰를 가지고 있는 뷰컨트롤러를 반환
optional func viewController(for interaction: UILargeContentViewerInteraction) -> UIViewContorller
}
Examples
button.showsLargeContentViewer = true
label.showsLargeContentViewer = true
customBar.addInteraction(UILargeContentViewerInteraction())
class MyCustomButton: UIView {
override var showsLargeContentViewer: Bool {
get {
return true
}
set { }
}
override var largeContentTitle: String? {
get {
return myTitle
}
set { }
}
override var largetContentImage: UIImage? {
get {
return mySmallImage
}
set { }
}
// pdf 이미지를 쓴다고 가정
override var scalesLargeContentImage: Bool {
get {
return true
}
set { }
}
}
longPressGesture를 이미 쓰고 있는 경우 겹치지 않게 하기
longPressRecognizer.minimumPressDuration = UILargeContentViewerInteraction.isEnabled ? 3.0 : 1.0
NotificationCenter.default.addObserver(forName: UILargeContentViewerInteraction.enabledStatusDisChangeNotification, object: nil, queue: nil) { _ in
longPressRecognizer.minimumPressDuration = UILargeContentViewerInteraction.isEnabled ? 3.0 : 1.0
}
longPressRecognizer.delegate = self
// delegate
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer == longPressRecognizer && otherGestureRecognizer == largeContentViewerInteraction.gestureRecognizerForExclusiveRelationShip
}