반응형

[최종 수정일 : 2018.05.05]

원문 : https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/SettingUpLayerObjects/SettingUpLayerObjects.html#//apple_ref/doc/uid/TP40004514-CH13-SW12

레이어 객체 설정하기(Setting Up Layer Objects)

레이어 객체는 코어 애니메이션으로 하는 모든 일들의 핵심입니다. 레이어는 앱의 시각적 컨텐츠를 관리하고 컨텐츠 스타일과 시각적인 표현을 수정하는 옵션을 제공합니다. iOS 앱의 경우에 레이어 지원이 자동으로 사용가능하지만, OS X 앱 개발자는 성능상의 혜택을 활용하기 전에 명시적으로 활성화 해야 합니다. 한번 활성화되면, 원하는 효과를 얻기 위해 앱의 레이어를 구성하고 조작하는 방법을 이해해야 합니다.

앱에서 코어 애니메이션 지원 활성화하기(Enabling Core Animation Support in Your App)

iOS 앱에서, 코어 애니메이션은 항상 활성화되고 뷰는 언제나 레이어 기반입니다. OS X에서, 앱은 다음을 수행하여 명시적으로 코어 에니메이션 지원을 활성화해야 합니다.

  • QuartzCore 프레임워크에 대해 연결(Link)합니다.(iOS 앱은 코어 애니메이션 인터페이스를 명시적으로 사용하는 경우에만 이 프레임워크를 연결해야 합니다.)
  • 다음 중 하나를 수행하여 NSView 객체 중의 하나 이상에 대해 레이어 지원을 활성화 합니다.
    • nib 파일에서, 뷰에 대한 레이어 지원을 활성화하기 위해 View Effects inspector를 사용합니다. inspector(속성 관리자)에서 뷰와 하위 뷰에 대해 체크박스가 선택되도록 표시합니다. 가능하면 윈도우의 컨텐츠 뷰에서 레이어 지원을 사용하도록 하는 것이 좋습니다.
    • 뷰에 대해 프로그래밍적으로 생성하는 경우, setWantsLayer: 메소드를 호출하고 뷰가 레이어를 사용하는 것을 나타내려면 YES값을 전달 합니다.

앞에서 설명한 레이어 기반 뷰(layer-backed view)를 만드는 방법중 하나를 사용하여 레이어를 지원 사용하도록 합니다. 레이어 기반 뷰(layer-backed view)로, 시스템은 기본 레이어 객체를 생성하고 업데이트된 상태로 유지하는 책임이 있습니다. OS X에서, 앱이 실제로 레이어 객체를 생성하고 관리하도록 레이어 호스팅 뷰(layer-hosting view)를 만들 수 있습니다. (iOS에서는 레이어 호스팅 뷰를 만들 수 없습니다.) 레이어 호스팅 뷰(layer-hosting view)를 생성하는 방법에 대해 더 자세한 정보는, OS X에서 
레이어 호스팅을 사용하여 레이어 객체를 변경하기(Layer Hosting Lets You Change the Layer Object in OS X)
를 보세요.

뷰와 연관된 레이어 객체 변경하기(Changing the Layer Object Associated witeh a View)

레이어 기반 뷰(Layer-backed view)는 기본적으로 CALayer 클래스의 인스턴스를 생성하고, 대부분의 경우 다른 타입의 레이어 객체가 필요하지 않을수 있습니다. 하지만, 코어 애니메이션은 다른 레이어 클래스를 제공하며, 각각은 유용한 특수 기능을 제공합니다. 다른 클래스를 선택하여 성능을 향상시키거나 간단한 방법으로 특정 타입의 컨텐츠를 지원할 수 있습니다. 예를들어, CATiledLayer 클래스는 큰 이미지를 효율적인 방법으로 표시하기 위해 최적화되어 있습니다.

UIView에서 사용되는 레이어 클래스 변경하기(Changing the Layer Class Used by UIView)

뷰의 layerClass 메소드를 재정의(override)하고 다른 객체를 반환하여, iOS 뷰에서 사용되는 레이어의 타입을 변경할 수 있습니다. 대부분의 iOS 뷰는 CALayer객체를 만들고 해당 레이어를 해당 컨텐츠의 보조 저장소(backing store)로 사용합니다. 여러분이 가진 대부분의 뷰에 대해, 기본(default) 선택이 좋고, 그것을 바꿀 필요가 없습니다. 그러나 특정 상황에서 다른 레이어 클래스가 더 적합하다는 것을 알수 있습니다. 예를 들어, 다음과 같은 상황에서 레이어 클래스를 변경할 수 있습니다.

  • Metal이나 OpenGL ES를 사용하여 뷰 컨텐츠를 그리며, 이 경우에 CAMetalLayer 또는 CAEAGLLayer 객체를 사용할 것입니다.
  • 더 나은 성능을 제공하는 특수한 레이어 클래스가 있습니다.
  • 파티클 발생기(particle emitters)나 복제기능(replicators) 같은 일부 특별한 코어 에니메이션 레이어 클래스를 이용하길 원합니다.

뷰의 레이어 클래스를 변경하는 것은 매우 간단(straightforward)합니다. [목록 2-1]에서 예제를 볼수 있습니다. layerClass 메소드를 재정의(overriding)하고 대신 사용하고 싶은 클래스 객체를 반환합니다. 디스플레이 전에, 자체적으로 새로운 레이어 객체를 만들기 위해 뷰는 layerClass메소드를 호출하고 반환된 클래스를 사용합니다. 한번 생성되면, 뷰의 레이어 객체는 변경되지 않습니다.

[목록 2-1] iOS 뷰의 레이어 클래스 지정하기

+ (Class) layerClass {
   return [CAMetalLayer class];
}

레이어 클래스 목록과 사용방법에 대해, 다른 레이어 클레스는 특별한 행동 제공하기(Different Layer Classes Provide Specialized Behaviors)를 보세요.

NSView에서 사용되는 레이어 클래스 변경하기(Changing the Layer Class Used By NSView)

makeBackingLayer 메소드를 재정의(overriding)하여 NSView 객체가 사용되는 기본 레이어 클래스를 변경할 수 있습니다. 이 메소드를 구현할때, AppKit에서 
사용자정의 뷰를 백업하는데 사용할 레이어 객체를 생성하고 반환합니다. 스크롤 또는 타일링된 레이어와 같은 사용자정의 레이어를 사용하려는 경우 이 메소드를 재정의 할 수 있습니다.

레이어 클래스 목록과 사용방법에 대해, 다른 레이어 클레스는 특별한 행동 제공하기(Different Layer Classes Provide Specialized Behaviors)를 보세요.

OS X에서 레이어 호스팅을 사용하여 레이어 객체를 변경하기(Layer Hosting Lets You Change the Layer Object in OS X)

레이어 호스팅(layer-hosting) 뷰는 NSView 레이어 객체를 만들고 관리하는 객체 입니다. 뷰와 관련된 레이어 객체의 타입을 제어하기 원하는 상황에서 레이어 호스팅(layer-hosting)을 사용할 수도 있습니다. 예를 들어, 기본 CALayer클래스보다 레이어 클래스를 할당할 수 있도록, 레이어 호스팅(layer-hosting) 뷰를 만들 수 있습니다. 독립적인 레이어의 계층을 관리하기 위해 단일 뷰를 사용하길 원하는 상황에서도 사용할 수 있습니다.

뷰의 setLayer: 메소드를 호출하고 레이어 객체를 제공할때, AppKit은 레이어에 접근하지 않습니다. 정상적으로, AppKit은 뷰의 레이어 객체를 업데이트 하지만 레이어 호스팅(layer-hosting) 상황에서는 대부분의 속성은 해당하지 않습니다.

레이어 호스팅(layer-hosting)을 만들기 위해, [목록 2-2]와 같이, 화면에 뷰를 표시하기 전에 레이어 객체를 만들고 뷰와 연관시킵니다. 레이어 객체를 설정하는것 외에도, setWantsLayer: 메소드를 호출하여 뷰가 레이어를 사용해야 한다는 것을 알 수 있어야 합니다.

[목록 2-2] 레이어 호스팅(layer-hosting) 뷰 만들기

// Create myView...
 
[myView setWantsLayer:YES];
CATiledLayer* hostedLayer = [CATiledLayer layer];
[myView setLayer:hostedLayer];
 
// Add myView to a view hierarchy.

스스로 호스트 레이어(host layers)를 선택하는 경우에, contentsScale 속성을 설정해야 하고 적절한 시간에 고해상도(high-resolution) 컨텐츠를 제공합니다. 고해상도(high-resolution) 컨텐츠와 스케일 요소에 관한 자세한 정보는, 고해상도 이미지로 작업하기(Working with High-Resolution Images)를 보세요.

다른 레이어 클레스는 특별한 행동 제공하기(Different Layer Classes Provide Specialized Behaviors)

코어 에니메이션은 많은 표준 레이어 클래스를 정의하며, 각각의 특정 사용사례(use case)를 위해 설계되었습니다. CALayer 클래스는 모든 레이어 객체의 루트(root) 클래스입니다. 모든 레이어 객체가 지원해야하는 동작을 정의하고 레이어 기반(layer-backed)의 뷰로 사용되는 기본 타입입니다. 하지만, 표 2-1에서 레이어 클래스 중 하나를 지정할 수 있습니다.

[표 2-1] CALayer 하위클래스와 용도

클래스사용법
CAEmitterLayer코어 에니메이션 기반의 파티클 발생 시스템을 구현하는데 사용됩니다.
CAGradientLayer레이어의 모양을 채우는 그라디언트 색상을 그릴때 사용됩니다(둥근 모서리 경계 안쪽으로)
CAMetalLayerMetal을 사용하여 레이어 컨텐츠를 그리는 그리기 가능한 텍스쳐(textures)를 설정하고 확장(vend)하는데 사용됩니다.
CAEAGLLayer/CAOpenGLLayerOpenGL ES (iOS) 또는 OpenGL (OS X)를 사용하여 레이어 컨텐츠를 그리기 위해 보조 저장소(backing store)와 컨텍스트(context)를 설정하는데 사용됩니다.
CAReplicatorLayer하나 이상의 하위 레이어의 복사본을 자동으로 만들기 원할때 사용됩니다.
CAScrollLayer여러개의 하위레이어로 구성된 큰 스크롤 영역을 관리하는데 사용됩니다.
CAShapeLayer큐빅 베지어 스플라인(cubic Bezier spline)을 그리기 위해 사용됩니다. 모양 레이어(Shape layers)는 항상 선명한(crisp) 패스(path)이기 때문에, 패스 기반(path-based) 모양을 그리는데 유리하며, 스케일(scaled)될때 잘 보이지 않는 레이어의 보조 저장소로 그려주는 패스와는 다릅니다. 하지만, 선명한(crisp) 결과는 메인 스레드에서 모양(shape) 그리기를 포함하고 결과를 캐싱(caching)합니다.
CATextLayer일반(plain) 텍스트 또는 attributed 문자열을 그리는데 사용됩니다.
CATiledLayer작은 타일로 나눌수 있는 큰 이미지를 관리하고 컨텐츠 확대(zooming)를 지원하여 개별적으로 그리는데 사용됩니다.
CATransformLayer다른 레이어 클래스에 의해 구현된 병합된 레이어 계층구조가 아닌, 진정한 3D 레이어 계층구조를 그리는데 사용됩니다.
QCCompositionLayerQuartz Composer 구성을 그리는데 사용됩니다. (OS X 에서만)

레이어의 컨텐츠 제공하기(Providing a Layer’s Contents)

레이어는 앱에서 제공하는 컨텐츠를 관리하는 데이터 객체입니다. 레이어의 컨텐츠를 표시하기 위한 시각적인 데이터가 포함된 비트맵으로 구성됩니다. 다음 세가지 방법중 하나를 사용하여 해당 비트맵의 컨텐츠를 제공할 수 있습니다.

  • 레이어 객체의 contents 속성에 직접 이미지 객체를 지정합니다. (이 기술은 절대 변경되지 않거나 거의 변경되지 않는 레이어 컨텐츠에 가장 적합합니다)
  • delegate 객체를 레이어에 할당하고 delegate가 레이어의 컨텐츠를 그릴수 있도록 합니다. (이 기술은 뷰와 같이, 주기적으로 바뀔수 있는 레이어에 가장 적합하고 외부 객체에 의해 제공될 수 있습니다)
  • 직접 레이어 컨텐츠를 제공하기 위해 레이어 하위클래스를 정의하고 그리는(drawing) 메소드중의 하나를 재정의합니다. (이 기술은 사용자정의 레이어 하위클래스를 만들어야하는 경우 또는 레이어의 기본 그리기 동작을 변경하길 원하는 경우에 적절합니다)

레이어에 컨텐츠를 제공하는 것에 대해 걱정할 필요가 있는 유일한 경우는 직접 레이어 객체를 만들때입니다. 앱 컨텐츠에 레이어 기반(layer-backed) 뷰만을 포함하는 경우, 레이어 컨텐츠를 제공하기 위해 이전 기술 중 하나를 사용하는 것에 대해 걱정할 필요가 없습니다.

레이어의 컨텐츠에 대한 이미지 사용하기(Using an Image for the Layer’s Content)

레이어는 단지 비트맵 이미지를 관리하기 위한 컨테이너 이기때문에, 레이어의 contents 속성에 직접 이미지를 할당할 수 있습니다. 레이어에 이미지 지정하는 것은 쉽고 화면에 표시할 정확한 이미지를 지정할 수 있습니다. 이 레이어는 직접 제공한 이미지 객체를 사용하고 해당 이미지의 자체 복사본을 만들려고하지 않습니다. 이러한 동작은 앱이 여러 곳에서 동일한 이미지를 사용하는 경우에 메모리를 절약할 수 있습니다.

레이어에 할당하는 이미지는 CGImageRef 타입이어야 합니다. (OS X v10.6 이후에, NSImage 객체를 할당할 수 있습니다) 이미지를 지정할때, 해상도가 기본 장치의 해상도와 일치하는 이미지를 제공해야 하는 것을 기억합니다. 레티나 디스플레이 기기의 경우, 이미지의 contentsScale 속성을 조정해야 할 수도 있습니다. 레이어로 고해상도(high-resolution) 컨텐츠를 사용하는 방법에 대한 자세한 내용은, 고해상도 이미지로 작업하기(Working with High-Resolution Images)를 보세요.

레이어의 컨텐츠를 제공하기 위해 Delegate 사용하기(Using a Delegate to Provide the Layer’s Content)

레이어의 컨텐츠가 동적으로 변경되는 경우, 필요할때 컨텐츠 제공하고 업데이트하기 위해 delegate 객체를 사용합니다. 디스플레이할때, 필요한 컨텐츠를 제공하기 위해 레이어는 delegate의 메소드를 호출합니다.

  • delegate가 displayLayer:메소드를 구현하는 경우, 그 구현은 비트맵을 만들고 레이어의 contents속성에 할당해야 합니다.
  • delegate가 drawLayer:inContext:메소드를 구현하는 경우, 코어 에니메이션은 비트맵을 생성하고, 해당 비트맵에 그리기위해 그래픽 컨텍스트(context) 만들고나서 비트맵을 채우기 위해 delegate 메소드를 호출합니다. 모든 delegate 메소드는 제공된 그래픽 컨텍스트(context)에 그려야 합니다.

delegate 객체는 반드시 displayLayer: 또는 drawLayer:inContext:메소드를 구현해야 합니다. delegate가 displayLayer:와 drawLayer:inContext:메소드 모두 구현하는 경우, 레이어는 displayLayer:메소드만 호출합니다.

displayLayer: 메소드 재정의는 디스플레이하기 위해 앱이 비트맵을 로드하거나 생성하려고 할때 상황에 가장 적합합니다. [목록 2-3]은 displayLayer: delegate 메소드의 샘플 구현을 보여줍니다. 이 예제에서, delegate는 필요한 이미지를 로드하고 디스플레이하기 위해 도우미 객체를 사용합니다. delegate 메소드는 자체 내부 상태에 따라 디스플레이할 이미지를 선택하며,

이 예제에서 displayYesImage라는 사용자 정의 속성입니다.

[목록 2-3] 레이어 컨텐츠를 직접 설정하기

- (void)displayLayer:(CALayer *)theLayer {
    // Check the value of some state property
    if (self.displayYesImage) {
        // Display the Yes image
        theLayer.contents = [someHelperObject loadStateYesImage];
    }
    else {
        // Display the No image
        theLayer.contents = [someHelperObject loadStateNoImage];
    }
}

비트맵을 만들기 위해 이미지를 미리 생성하지 않거나 도우미 객체가 없는 경우에, delegate는 drawLayer:inContext:메소드를 사용하여 컨텐츠를 동적으로 그릴수 있습니다. [목록 2-4]는 drawLayer:inContext: 메소드의 샘플 구현을 보여줍니다. 이 예제에서, delegate는 고정 넓이와 현재 랜더링 색상을 사용하여 간단한 곡선 패스(curved path)를 그립니다.

[목록 2-4] 레이어의 컨텐츠 그리기

- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext {
    CGMutablePathRef thePath = CGPathCreateMutable();
 
    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath,
                          NULL,
                          15.f,250.0f,
                          295.0f,250.0f,
                          295.0f,15.0f);
 
    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath);
 
    CGContextSetLineWidth(theContext, 5);
    CGContextStrokePath(theContext);
 
    // Release the path
    CFRelease(thePath);
}

사용자 정의 컨텐츠가 있는 레이어 기반(layer-backed)의 뷰의 경우에, 드로잉하기 위해 뷰의 메소드를 계속 재정의해야 합니다. 레이어 기반(layer-backed)의 뷰는 자동적으로 자신의 해당 레이어의 delegate로 만들고 필요한 delegate 메소드를 구현하고, 해당 구성을 변경해서는 안됩니다. 대신에, 컨텐츠를 그리기 위해 뷰의 drawRect:메소드를 구현합니다.

OS X 10.8 이후에, 드로잉 대안은 뷰의 wantsUpdateLayer와 updateLayer 메소드 재정의하여 비트맵을 제공하는 것입니다. wantsUpdateLayer를 재정의하고 YES를 반환하면 NSView 클래스가 
대체 랜더링 패스(path)를 따르게 됩니다. drawRect:호출하는 대신에, updateLayer메소드를 호출하며, 이 구현에서 레이어의 contents 속성에 직접 비트맵을 할당해야 합니다. AppKit에서 뷰의 레이어 객체의 컨텐츠를 직접 설정해야 하는 시나리오 입니다.

서브클래싱을 통해서 레이어 컨텐츠 제공하기(Providing Layer Content Through Subclassing)

사용자 정의 레이어 클레스를 구현하는 경우에, 그리기 위해 레이어 클래스의 그리기(drawing) 메소드를 재정의(override) 할 수 있습니다. 레이어 객체가 사용자정의 컨텐츠를 자체적으로 생성하는게 흔치않지만, 레이어는 컨텐츠를 표시하는 것을 확실히 관리할 수 있습니다. 예를들어, CATiledLayer 클래스는 그릴수 있는 작은 타일(tiles)로 쪼개서 관리하고 개별적으로 표시(randered)하여 커다란 이미지를 관리합니다. 그 레이어는 타일(tiles)을 주어진 시간에 그려야하는 정보만 있기 때문에, 그리는 동작을 직접 관리합니다.

서브클래싱(subclassing) 할때, 레이어의 컨텐츠를 그리기 위해 다음에 오는 기술중 하나를 사용할 수 있습니다.

  • 레이어의 display메소드를 재정의(override)하고 레이어의 contents 속성을 직접 설정할때 사용합니다.
  • 레이어의 drawInContext:메소드를 재정의하고, 이를 사용하여 제공된 그래픽 컨텐츠를 그릴때 사용합니다.

메소드를 재정의 하는 것은 그리기 처리(drawing process)에 필요한 컨트롤의 양에 따라 다릅니다. display메소드는 레이어 컨텐츠를 업데이트하기 위한 주요 진입점이기에, 이 메소드를 재정의하면 처리(process)하는것을 완전히 제어할수 있습니다. display 메소드를 재정의 하는 것은 contents속성에 할당하기 위해 CGImageRef를 생성해야 하는 것을 의미합니다. 컨텐츠 그리기 (또는 레이어에서 그리는 작업을 관리) 를 원하는 경우에, drawInContext: 메소드를 재정의하고 레이어에서 백업 저장소를 생성 할수 있습니다.

제공하는 컨텐츠 조정하기(Tweaking the Content You Provide)

레이어의 contents 속성에 이미지를 할당할때, 레이어의 contentsGravity 속성은 이미지가 현재 경계에 알맞게 조정되는 방법을 결정합니다. 기본적으로, 이미지가 현재 경계보다 더 크거나 작은경우, 레이어 객체는 사용가능한 공간에 맞게 이미지의 비율(scales)을 조절합니다. 레이어 경계의 종횡비(aspect ratio)가 이미지의 종횡비(aspect raito)와 다른경우에, 이미지가 왜곡될수 있습니다. 컨텐츠가 가능한 한 최상의 방법으로 표시되는것을 보장(ensure)하기 위해 contentsGravity속성을 사용할 수 있습니다.

contentGravity속성이에 지정할 수 있는 값은 두가지로 나뉩니다.

  • 위치 기반(position-based)의 비중 상수(gravity constants)는 이미지의 비율(scales)을 조정하지 않고 이미지를 레이어의 경계 사각형의 특정 가장자리나 모서리에 고정할 수 있습니다.
  • 비율 기반(scaling-based)의 비중 상수(gravity constants)는 이미지를 늘리는(stretch) 몇 가지 옵션중 하나를 사용하며, 일부는 종횡비(aspect ratio)를 유지하고 일부는 유지하지 않습니다.

[그림 2-1]은 위치 기반(position-base)의 비중 설정이 이미지에 미치는 영향을 보여줍니다. kCAGravityCenter 상수를 제외하고, 각 상수는 레이어의 경계 사각형의 특정 가장자리나 모서리에 이미지를 고정합니다. kCAGravityCenter상수는 레이어에 있는 이미지 가운데 입니다. 이러한 상수중 어느 것도 이미지를 어떤 방법으로든 비율(scaled)을 조절하지 못하게 하며, 이미지는 항상 원래 크기로 그려(rendered)집니다. 이미지가 레이어 경계보다 더 큰 경우에, 이미지의 일부가 잘리게(clipped) 되고, 이미지가 더 작은 경우에, 이미지가 없는 레이어 부분은 레이어의 배경색(설정한 경우에)이 보일 것입니다.

[그림 2-1] 레이어에 대한 위치 기반의 비중 상수


[그림 2-2]는 비율 기반(scaling-based)의 비중 상수가 이미지에 미치는 영향을 보여줍니다. 이러한 모든 상수는 레이어의 경계 사각형에 정확히 맞지 않으면 이미지 비율을 조절합니다. 이러한 모드(modes) 간의 차이는 이미지의 원래 종횡비(aspect ratio)를 다루는 방법입니다. 일부 모드는 유지하고 일부는 그렇지 않습니다. 기본적으로, 레이어의 contentsGravity속성은 이미지의 종횡비(aspect ratio)를 유지하지 않는 유일한 모드인 kCAGravityResize 상수로 설정합니다.

[그림 2-2] 레이어에 대한 비율 기반의 비중 상수


고해상도 이미지로 작업하기(Working with High-Resolution Images)

레이어에는 디바이스의 화면 해상도에 대한 고유한 정보를 가지고 있지 않습니다. 레이어는 단순히 비트맵에 대한 포인터를 저장하고 가능한 한 최상의 방법으로 사용할수 있는 픽셀을 표시합니다. 레이어의 contents 속성에 이미지를 할당하는 경우, 이미지 해상도에 관해 레이어의 contentsScale의 속성에 적절한 값을 설정하여 코어 에니메이션에 알려야 합니다. 그 속성의 기본 값은 표준 해상도 화면에 표시하는 이미지에 적합한 1.0입니다. 이미지가 레티나(Retina) 디스플레이용인 경우에는 이 속성의 값을 2.0으로 설정합니다.

contentsScale 속성의 값 변경은 레이어에 직접 비트맵을 할당하는 경우에만 필요합니다. UIKit과 AppKit에 있는 레이어기반의 뷰는 화면 해상도와 뷰에서 관리하는 내용에 따라 적절한 값으로 설정하기 위해, 자동으로 레이어의 비율 인자를 설정합니다. 예를들어, OS X에서 레이어의 contents속성에 NSImage 객체를 할당하는 경우, AppKit은 이미지의 표준 또는 고해상도 변형(variants)이 있는지 확인합니다. 그런 경우에, AppKit은 현재 해상도에 대해 올바른 변형을 사용하고 contentScale속성 값을 일치하도록 설정합니다.

OS X에서, 위치 기반의 비중 상수는 레이어에 할당된 NSImage객체에서 선택된 이미지 표현하는 방식에 영향을 줍니다. 이 상수는 비율이 조절되지 않기 때문에, 코어 에니메이션은 contentScale속성을 사용하여 가장 어울리는 픽셀 밀도(pixel density)를 선택하여 이미지를 표현합니다.

OS X에서, 레이어의 델리게이터(delegate)는 layer:shouldInheritContentsScale:fromWindow:메소드를 구현하고 비율 값(scale factor)을 변경하는데 사용할 수 있습니다. AppKit은 윈도우가 표준해상도와 고해상도 화면사이간에 이동했을수 있기 때문에, 윈도우에 대한 해상도가 변경될때마다 자동적으로 메소드를 호출합니다. 델리게이터(delegate)가 레이어의 이미지 해상도를 변경하는 것을 지원하는 경우, 이 메서드 구현은YES를 반환해야 합니다. 이 메소드는 새로운 해상도를 반영하기 위해 필요한 경우 레이어의 컨텐츠를 업데이트해야 합니다.

레이어의 시각적 스타일과 모양 조정하기(Adjusting a Layer’s Visual Style and Apperarance)

레이어 객체들은 레이어의 주요 컨텐츠를 지원하는데 사용할 수 있는 테두리(border)와 배경색(background color)과 같은 시각적인 장식(adornments)을 가지고 있습니다. 이러한 시각적인 장식은 사용자가 그릴(randering)필요가 없기 때문에, 어떤 상황에서는 독립적인 요소로 레이어를 사용할 수 있습니다. 레이어에 있는 속성들을 설정하고 레이어에서 에니메이션을 포함해서, 필요한 그리기를 처리하기만하면 됩니다. 이러한 시각적인 장식이 레이어 모양에 어떤 영향을 미치는지에 대한 추가적인 일러스트는, 레이어 스타일 속성 에니메이션(Layer Style Property Animations) 를 보세요.

레이어는 고유한 배경색과 테두리를 가집니다(Layers Have Their Own Background and Border)

레이어는 이미지 기반의 컨텐츠 외에도 배경 채우기와 테두리선을 표시할 수 있습니다. [그림 2-3]에서 보는 것처럼, 배경 색상은 레이어의 컨첸츠 이미지 뒤에 그려지고 테두리는 이미지의 위에 그려집니다. 레이어가 하위레이어를 포함하는 경우에, 그것들은 테두리 아래에 나타납니다. 배경 색상은 이미지 뒤에 있기 때문에, 그 색상은 이미지의 투명한 부분을 통해서 보여(shines)집니다.

[그림 2-3] 레이어에 테두리와 배경을 추가하기


[목록 2-5]는 레이어의 배경색과 테두리를 설정하는데 필요한 코드를 보여줍니다. 이러한 속성은 에니메이션이 가능합니다.

[목록 2-5] 레이어의 배경색상과 테두리 설정하기

myLayer.backgroundColor = [NSColor greenColor].CGColor;
myLayer.borderColor = [NSColor blackColor].CGColor;
myLayer.borderWidth = 3.0;

주의
레이어의 배경에는 투명도가 있거나 패턴 이미지를 사용하는 색상을 포함하여, 모든 타입의 색상을 사용할 수 있습니다. 패턴 이미지를 사용할때, Core Graphics는 패턴 이미지의 랜더링을 처리하고 iOS의 기본 좌표계와는 다른 표준 좌표계를 사용합니다. 이와 같이 iOS에서 그려진 이미지는 좌표를 뒤집지 않으면 기본적으로 거꾸로(upside down) 표시됩니다.

레이어의 배경 색상을 불투명한 색상으로 설정한 경우, 레이어의 불투명 속성을 YES로 설정하는 것이 좋습니다. 레이어를 화면에 구성할때 성능을 향상시킬수 있고 투명도(alpha channel)를 관리하기 위해 레이어의 백업 저장소가 필요하지 않습니다. 모서리 반경(corner radius)이 0이 아닌 값을 가지고 있는 경우에, 레이어를 불투명으로 표시하면 안됩니다.

레이어의 모서리 반경 지원(Layer Support a Corner Radius)

레이어에 모서리 반경(corner radius)을 추가하여 둥근 사각형 효과를 만들수 있습니다. [그림 2-4]에서 보는 것처럼, 모서리 반경(corner radius)은 레이어 경계 사각형을 마스킹(masks)하여 기본 컨텐츠를 표시할수 있는 시각적 장식(visual adornment)입니다. 투명도 마스크도 포함하여 적용하기 때문에, masksToBounds 속성이 YES로 설정되어 있지 않으면 모서리 반경은 레이어어의 contents속성에 있는 이미지에 영향을 주지 않습니다. 하지만, 모서리 반경(corner radius)은 항상 레이어의 배경색과 테두리에 영향을 줍니다.

[그림 2-4] 레이어에서의 모서리 반경


레이어에 모서리 반경을 적용하기위해, 레이어의 cornerRadius 속성에 값을 지정합니다. 지정한 반경(radius) 값은 포인트단위로 측정되며, 표시하기 전에 레이어의 모서리 네군데에 적용됩니다.

레이어의 그림자 지원(Layers Support Built-in Shadows)

CALayer 클래스는 그림자 효과를 설정하는 몇가지 속성을 포함하고 있습니다. 그림자는 컨텐츠 아래에 떠있는 것처럼 보이게 만들어 레이어에 깊이(depth)를 줍니다. 이것은 앱에서 특정 상황에서 유용하게 사용할 수 있는 또 다른 시각적인 장식(visual adornment)입니다. 레이어를 사용하여 레이어의 컨텐츠, 불투명도와 모양과 관련된 그림자의 색상, 위치를 제어할 수 있습니다.

레이어 그림자의 불투명도(opacity) 값은 기본적으로 그림자 효과를 숨기는0으로 설정되어 있습니다. 불투명도를 0이 아닌 값으로 변경하면 코어 에니메이션은 그림자를 그립니다. 그림자는 기본적으로 레이어 바로 아래에 위치하기 때문에, 그림자의 간격(offset)을 변경해야 할수도 있습니다.그림자에 대해 지정한 간격(offset)은 iOS와 OS X의 좌표계가 다르기 때문에, 레이어의 고유 좌표계를 사용하여 적용되는 것을 기억해야 합니다. [그림 2-5]에서 레이어의 아래와 오른쪽으로 뻗어있는 그림자가 있는 레이어를 보여줍니다. iOS 에서, y축에 양수(positive) 값을 지정해야 하지만, OS X에서는 음수(negative) 값이 필요합니다.

[그림 2-5] 레이어에 그림자 적용하기


레이어에 그림자를 추가할때, 그림자는 레이어 컨텐츠의 일부이지만 실제로는 레이어 경계 사각형 밖으로 뻗어나갑니다. 결과적으로 레이어에 masksToBounds속성이 사용가능하면, 그림자 효과는 가장자리 주변으로 잘리게(clipped) 됩니다. 레이어가 투명한 컨텐츠를 가지고 있는 경우에, 레이어 바로 아래의 그림자 부분은 보이지만 레이어를 벗어나는 부분은 보이지 않는 이상한 효과가 될수 있습니다. 경계 마스킹(bounds masking)을 사용하여, 그림자를 원하는 경우에는, 하나 대신 두개의 레이어를 사용합니다. 컨텐츠가 포함된 레이어에 마스킹(mask)을 적용하고나서 해당 레이어와 동일한 크기의 그림자 효과를 활성화한 두번째 레이어를 포함합니다.

어떻게 레이어에 그림자를 적용는지에 대한 예제는 그림자 속성(Shodow Properties)를 보세요.

OS X 뷰에 시각 효과 필터 추가하기(Filters Add Visual Effects to OS X Views)

OS X 앱에서, 레이어의 컨텐츠에 코어 이미지(Core Image) 필터를 직접 적용할 수 있습니다. 레이어의 컨텐츠를 흐리게하거나(blur) 선명하게(sharpen) 하거니, 색상을 변경하거나, 컨텐츠를 왜곡(distort)하거나, 다른 많은 종류의 작업을 처리할 수 있습니다. 예를들어, 이미지 처리 프로그램에 이미지를 변경하지 않고 이러한 필터를 사용할 수 있고 비디오 편집 프로그램에는 다양한 종류의 비디오 전환 효과를 구현할수 있습니다. 그리고 필터는 하드웨어의 레이어 컨텐츠에 적용되므로 그리기(randering)가 빠르고 부드럽습니다.

주의
iOS에서는 레이어 객체에 필터를 추가할 수 없습니다.

주어진 레이어에 대해, 레이어의 전경(foreground)과 배경(background) 컨텐츠 양쪽에 필터를 적용할 수 있습니다. 전경(foreground) 컨텐츠는 contents속성에 있는 이미지, 배경 색상, 테두리, 하위 레이어의 컨텐츠를 포함하여, 레이어 자체적으로 포함된 모든 항목으로 구성됩니다. 배경(background) 컨텐츠는 레이어 바로 아래에 있지만 실제로 레이어 자체의 일부가 아닌 컨텐츠를 포함합니다. 대부분의 배경(background) 컨텐츠는 바로 레이어에 의해 전체 또는 부분적으로 가려질수 있는 상위 레이어의 컨텐츠입니다. 예를들어, 사용자가 레이어의 전경 컨텐츠에 집중하길 원한다면, 배경 컨텐츠에 흐려지는(blur) 필터를 적용할 수 있습니다.

레이어의 다음 속성에 CIFilter객체를 주가하여 필터를 지정할 수 있습니다.

  • filters 속성은 레이어의 전경 컨텐츠에만 영향을 주는 필터의 배열이 포함되어 있습니다.
  • backgroundFilters속성은 레이어의 배경 컨텐츠에만 영향을 주는 필터의 배열이 포함되어 있습니다.
  • compositingFilter 속성은 레이어의 전경과 배경 컨텐츠를 함께 합성하는 방법을 정의 합니다.

레이어에 필터를 추가히기 위해, 먼저 CIFilter객체를 찾아 생성하고 나서 레이어에 추가하기 전에 구성해야 합니다. CIFilter 클래스는 filterWithName:메소드 처럼, 사용가능한 코어 이미지(Core Image) 필터를 찾기 위한 클래스 메소드 몇 가지를 포함하고 있습니다. 이것은 필터를 만드는 첫 걸음일 뿐입니다. 많은 필터들은 필터가 이미지를 수정하는 방법을 정의하는 매개변수를 가지고 있습니다. 예를 들어, box blur 필터는 적용되는 흐림(blur) 효과에 영향을 주는 입력 반경 매개변수가 있습니다. 어러한 매개변수 값은 필터 구성 처리의 일부로 항상 제공해야 합니다. 하지만, 지정하지 않아도 되는 하나의 공통 매개변수는 레이어 자체적으로 제공되는 이미지 입력입니다.

레이어에 필터를 추가할때, 레이에 필터를 추가하기 전에 필터 매개변수를 구성하는 것이 가장 좋습니다. 이렇게 하는 주된 이유는 일단 레이어에 추가되면, CIFilter 객체 자체를 수정할 수 없기 때문입니다. 하지만, 이후에 필터 값을 변경하려면 레이어의 setValue:forKeyPath: 메소드를 사용할 수 있습니다.

[목록 2-6] 에서 레이어 객체에 핀치 왜곡(pintch distorion) 필더를 만들고 적용하는 방법을 보여줍니다. 이 필터는 레이어의 원본 픽셀을 안쪽(inward)으로 집어(pinches) 넣으며, 지정된 중앙 점에 가까운 픽셀을 가장 왜곡(distorting) 시킵니다. 이 예제에서는 레이어의 이미지가 자동으로 사용되기 때문에 필터의 입력 이미지를 적용할 필요가 없습니다.

[목록 2-6] 레이어에 필터 적용하기

CIFilter* aFilter = [CIFilter filterWithName:@"CIPinchDistortion"];
[aFilter setValue:[NSNumber numberWithFloat:500.0] forKey:@"inputRadius"];
[aFilter setValue:[NSNumber numberWithFloat:1.25] forKey:@"inputScale"];
[aFilter setValue:[CIVector vectorWithX:250.0 Y:150.0] forKey:@"inputCenter"];
 
myLayer.filters = [NSArray arrayWithObject:aFilter];

사용가능한 코어 이미지(Core Image) 필터들에 관해 정보는 Core Image Filter Reference를 보세요.

OS X 뷰의 성능에 영향을 주는 레이어 다시그리기 정책(The Layer Redraw Policy for OS X Views Affects Performance)

OS X에서, 레이어 기반의 뷰들은 기본 레이어의 컨텐츠를 업데이트할때를 결정하기 위한 몇가지 다른 정책을 지원합니다. AppKit 그리기 모델(drawing model)과 코어 에니메이션(Core animation)에서 도입한 모델간에 차이점이 있기 때문에, 이러한 정책들은 이전 코드를 코어 에니메이션(Core animation)으로 쉽게 마이그레이션 할 수 있습니다. 이러한 정책들은 각 뷰들에 대해 최상의 성능을 보장하기 위해 뷰 단위로(view-by-view)로 구성할 수 있습니다.

각 뷰는 뷰의 레이어에 대한 다시 그리기 정책을 반환하는 layerContentsRedrawPolicy메소드를 정의 합니다. setLayerConentsRedrawPolicy:메소드를 사용하여 정책을 설정합니다. 기존의 그리기 모델과의 호환성을 위채, AppKit은 기본적으로 NSViewLayerContentsRedrawDuringViewResize로 다시 그리기 정책을 설정합니다. 하지만, [표 2-2]에 있는 값으로 정책을 변경할 수 있습니다. 권장되는 다시 그리기 정책은 기본 정책이 아닌 것을 주의합니다.

[표 2-2] OS X 뷰에 대한 레이어 다시 그리기 정책

정책(Policy)사용법(Usage)
NSViewLayerContentsRedrawOnSetNeedDisplay권장된 정책입니다. 이 정책으로, 뷰의 형태(geometry) 변경으로 뷰가 레이어의 컨텐츠를 자동으로 업데이트 하지 않습니다. 그 대신에, 레이어의 기존 컨텐츠는 형태 변경이 용이하도록 늘려지고(stretched) 조작(manipulated)됩니다. 뷰를 강제로 다시 그려서 레이어의 컨텐츠를 업데이트 하려면, 뷰의 setNeedsDisplay: 메소드를 명시적으로 호출해야 합니다. 이 정책은 코어 에니메이션 레이어의 표준 동작을 가장 잘 나타냅니다. 하지만, 기본 정책이 아니라 반드시 명시적으로 설정해줘야 합니다.
NSViewLayerContentsRedrawDuringViewResize기본적인 다시그리기 정책입니다. 이 정책은 뷰의 형태가 변경될때마다 레이어의 컨텐츠를 다시 캐싱하며, 기존의 AppKit 그리기(drawing)와 호환성을 최대한 유지합니다. 크기가 조정되는 동안에 이 동작으로 인해 앱의 메인스레드에서 뷰의 drawRect: 메소드가 여러번 호출됩니다.
NSViewLayerContentsRedrawBeforeViewResize이 정책으로, AppKit은 레이어 크기 조정하기 전에 최종 크기로 그리고(draw) 비트맵을 캐쉬합니다. 크기 조정 작업은 캐쉬된 이미지를 시작된 이미지처럼 사용하며, 이전 경계 사각형에 맞게 크기를 조정합니다. 그런 다음에 비트맵을 최종 크기로 에니메이션합니다. 이 동작으로 에니메이션 시작부분에서 뷰의 컨텐츠가 늘어나거나 왜곡될수 있고 초기 모습이 중요하지 않거나 눈에 띄지 않는 상황에 더 어울립니다.
NSViewLayerContentsRedrawNever이 정책으로, AppKit은 레어어를 전혀 업데이트하지 않습니다. 심지어는 setNeedsDisplay: 메소드를 호출할때에도 마찬가지 입니다. 이 정책은 컨텐츠가 변하지 않는 뷰와 뷰의 크기가 자주 변경되지 않는 뷰에 가장 어울립니다. 예를 들어, 코정된 크기의 컨텐츠나 배경 요소를 표시하는 경우에 사용할 수 있습니다.

뷰의 다시그리기(redraw) 정책은 독립적인 하위레이어(sublayers)에 사용하여 그리기 성능을 향상시켜야 하는 필요성을 줄여(alleviate)줍니다. 뷰의 다시 그리기 정책을 도입하기 전에, 필요이상으로 자주 그려지고 성능 문제가 발생하는 레이어 기반(layer-backed)의 뷰들이 있었습니다. 이러한 성능상 문제에 대한 해결책은 하위 레이어를 사용하여 정규적인 다시 그리기가 필요하지 않는 뷰의 컨텐츠 부분을 표시하는 것입니다. OS X v16.0에서 명시적으로 하위 레이어 구조를 만드는 대신에 레이어 지원하는 뷰의 다시 그리기 정책을 적절한 값으로 설정하는 것이 좋습니다.

레이어에 사용자정의 속성 추가하기(Adding Custom Properties to a Layer)

CAAnimation과 CALayer 클래스는 사용자정의 속성을 지원하기 위해 키-값(key-value) 코딩 규칙을 확장합니다. 레이어에 데이터를 추가하기 위해 이 동작을 사용하고 정의한 사용자정의 키를 사용하여 검색(retrieve)할 수 있습니다. 속성을 변경할때 해당 에니메이션이 수행되도록 사용자정의 속성을 연결할수도 있습니다.

사용자정의 속성을 설정하고 가져오는 방법에관한 자세한 설명은, 키-값 코딩 준수 컨테이너 클래스(Key-Value Coding Compliant Container Classes)를 보세요. 레이어 객체에 추가하는 동작에 관한 정보에 대해서, 레이어의 기본 동작 변경하기(Changing a Layer’s Default Behavior)을 보세요.

레이어 기반의 뷰의 컨텐츠 인쇄하기(Printing the Contents of a Layer-Backed View)

인쇄하는 동안에, 레이어는 인쇄 환경을 수용하기 위해 필요에 따라 내용을 다시 그립니다. 코어 에니메이션은 일반적으로 화면에 그릴때(rendering) 캐시된 비트맵에 의존하지만, 인쇄할때 컨텐츠를 다시 그립니다. 특히, 레이어 기반 뷰가 레이어 컨텐츠를 제공하기 위해 drawRect: 메서드를 사용하며, 코어 에니메이션은 인쇄 도중에 drawRect:를 다시 호출하여 인쇄된 레이어 컨텐츠를 생성합니다.

반응형
Posted by 까칠코더
,