2014년 12월 4일 목요일

NSView의 좌표계(Coordinate System) 뒤집기

NSView 클래스를 상속받아서 커스텀한 뷰를 만드는 상황을 가정하자. 이 뷰는 인터페이스 빌더가 아닌 코드로 UI를 구성한다. 그런데 코드로 생성하는 자식뷰의 Y좌표를 0으로 하니 제일 바닥에 자식뷰가 붙었다. 이건 iOS의 UIView 와 비교해서 위 아래가 반대로 뒤집한 상황이다.

[참고] 이 글은 NSView Cheatsheet 글에 요약해서 정리되어 있다.

NSView는 기본 좌표계(Coordinate System)가 그래프 방식과 유사하게 되어있다. 즉 Y가 0이면 제일 아래에 위치한다.

상황에 따라 다르겠지만, 이런 위 아래가 상반되는 좌표계는 분명 잇점이 있을 때도 있고 없을 때도 있을 것이다. 예를 들자면, 특정 순서로 버튼을 위에서 아래로 배치하고 싶은데 Y좌표를 0 부터 계산하려면 결국 버튼 붙이는 순서를 반대로 해야한다. 하지만 그래프를 그릴 때라면 오히려 그래프좌표계가 더 편할 것이다.

해법을 찾기 위해 레퍼런스 문서를 뒤져보자. NSView 문서를 찾아보면 flipped 라는 읽기 전용 프로퍼티를 확인 할 수 있다.
flipped: A Boolean value indicating whether the view uses a flipped coordinate system. (read-only). The default value of this property is NO.
기본값이 NO(false), 즉 그래프 좌표계로 세팅되어 있다. 이 값이 YES라면 iOS의 좌표계와 유사한, 0이 상단으로 오게 만들 수 있다.

그런데 이 프로퍼티는 읽기 전용(read-only) 이기 때문에  그냥 세팅하기 위한 용도가 아니다. 그래서 문서에서 친절하게 해답을 제시하고 있다.
If you want your view to use a flipped coordinate system, override this property and return YES.
문서 내용대로 오버라이드로 해결해보자. 아래는 CustomView 라는 NSView 의 자식클래스 예제코드이다.
// Swift Code

class CustomView: NSView {
    ...
    override var flipped: Bool { return true }
    ...
}
// Objective-C Code

@interface CustomView: NSView
...
@end

@implementation CustomView
...
- (BOOL)isFlipped {
    return YES;
}
...
@end
이런 식으로 flipped 프로퍼티가 YES(true)를 알려주도록 세팅하면 이제 좌표계의 위/아래가 뒤집힌다. 즉 Y가 0이라면 제일 상단을 가리키게 된다.

Swift를 사용 할 때와 Objective-C를 사용 할 때 이름이 좀 다르다. 이유는 Objective-C의 flipped 라는 프로퍼티의 getter가 isFlipped 로 규정되어 있기 때문이다. 문서 내용을 잘 읽어봤다면 프로퍼티 선언부 내용으로 파악 할 수 있다.
@property(getter=isFlipped, readonly) BOOL flipped
'getter=isFlipped' 라고 적혀져있다. 따라서 이 flipped 프로퍼티의 getter 메소드 이름은 isFlipped 이다.

이 글을 작성하게까지 만들어 준 애플의 철학에 빅엿을 날리고 싶어졌다. 왜 iOS와 OS X 사이를 이렇게 다르게 해서 삽질을 하게 만드는지 원... -_-; (물론 이유는 있겠지만...)

댓글 없음 :