programing

iOS: Using UIView's 'drawRect:' vs. its layer's delegate 'drawLayer:inContext:'

codeshow 2023. 9. 14. 23:42
반응형

iOS: Using UIView's 'drawRect:' vs. its layer's delegate 'drawLayer:inContext:'

나는 하위 클래스인 수업이 있습니다.UIView. 뷰 내부에 있는 것을 구현하여 그릴 수도 있습니다.drawRect방법 또는 구현을 통해drawLayer:inContext:이것은 의 대리인 방법입니다.CALayer.

I have two questions:

  1. How to decide which approach to use? Is there a use case for each one?
  2. 구현할 경우drawLayer:inContext:, 라고 합니다.drawRect적어도 브레이크 포인트를 두는 것으로 알 수 있는 한), 비록 내가 내 견해를 다음과 같이 부여하지 않더라도.CALayer다음을 사용하여 위임합니다.

    [[self layer] setDelegate:self];

    내 인스턴스가 계층의 위임자로 정의되지 않은 경우 위임자 메서드를 호출하는 이유는 무엇입니까?그리고 어떤 메커니즘이 우리가drawRect라고 불려질 때부터drawLayer:inContext:불렸습니까?

How to decide which approach to use? Is there a use case for each one?

항상사용drawRect:, 그리고 절대로 a를 사용하지 않습니다.UIView모든 추첨 대리로서CALayer.

내 인스턴스가 계층의 위임자로 정의되지 않은 경우 위임자 메서드를 호출하는 이유는 무엇입니까?그리고 어떤 메커니즘이 drawRect를 다음과 같이 부르지 못하게 합니까?drawLayer:inContext:불렸습니까?

모든UIView인스턴스(instance)는 해당 백업에 대한 도면 대리인입니다.CALayer. 그래서.[[self layer] setDelegate:self];아무것도 하지 않는 것 같았습니다.그것은 중복입니다. 그.drawRect:메서드는 뷰 계층에 대한 도면 대리인 메서드입니다.내부적으로.UIView기구들drawLayer:inContext:자기 일을 하고 나서 전화를 하는 곳에서drawRect:. 디버거에서 확인할 수 있습니다.

drawRect: stacktrace

그래서.drawRect:당신이 구현할 때 호출된 적이 없습니다.drawLayer:inContext:. 이것은 또한 당신이 어떠한 것도 실행해서는 안 되는 이유이기도 합니다.CALayer사용자 정의에서 대리인 메서드 그리기UIView아류의또한 다른 도면층에 대한 도면 대리인을 볼 수 없습니다.그것은 모든 종류의 익살스러움을 야기할 것입니다.

구현하는 경우drawLayer:inContext:당신이 접속해야 하기 때문에CGContextRef, 당신은 당신의 안에서 그것을 얻을 수 있습니다.drawRect:전화로UIGraphicsGetCurrentContext().

drawRect반드시 필요한 경우에만 실행해야 합니다.기본 구현:drawRect보기의 렌더링을 지능적으로 캐싱하는 것과 같은 여러 가지 스마트 최적화 기능이 포함되어 있습니다.우선순위를 정하는 것은 모든 최적화를 우회하는 것입니다.큰일이네요.레이어 드로잉 방법을 효과적으로 사용하면 거의 항상 커스텀보다 성능이 뛰어납니다.drawRect. 애플은 a를 사용합니다.UIView의 대표로서CALayer모든 UIView가 해당 계층의 대리인인 경우가 많습니다.UI 내부 레이어 도면을 사용자 정의하는 방법을 확인할 수 있습니다. (현재) 줌잉을 포함한 여러 Apple 샘플에서 보기PDF 뷰어.

를 하는 하는의 사용 중drawRect일반적으로, 적어도 2002/2003년 이후로 권장되지 않는 관행입니다, IIRC.그 길을 가야 할 마땅한 이유가 별로 남아 있지 않습니다.

아이폰 OS에서 고급 성능 최적화 (슬라이드 15)

핵심 애니메이션 에센셜

UIKit 렌더링의 이해

기술 Q&A QA1708: iOS에서의 이미지 그리기 성능 향상

뷰 프로그래밍 가이드: 뷰 도면 최적화

다음은 샘플 줌잉 코드입니다.Apple의 PDF 뷰어:

-(void)drawRect:(CGRect)r
{

    // UIView uses the existence of -drawRect: to determine if it should allow its CALayer
    // to be invalidated, which would then lead to the layer creating a backing store and
    // -drawLayer:inContext: being called.
    // By implementing an empty -drawRect: method, we allow UIKit to continue to implement
    // this logic, while doing our real drawing work inside of -drawLayer:inContext:

}

-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
    ...
}

drawLayer(_:inContext:)아니면drawRect(_:)사용자 지정 도면 코드의 경우 도면층 속성이 애니메이션화되는 동안 현재 값에 액세스해야 하는지 여부에 따라 달라집니다.

는 오늘 저만의 Label 클래스를 구현할 때 이 두 가지 기능과 관련된 다양한 렌더링 문제로 어려움을 겪었습니다.설명서를 확인하고 몇 가지 시행착오를 거치고 UIKit의 컴파일을 해제하고 Apple의 Custom Animatable Properties 예제를 검사한 결과 작동 방식에 대한 좋은 감각을 얻었습니다.

drawRect(_:)

애니메이션이 진행되는 동안 레이어/뷰 속성의 현재 값에 액세스할 필요가 없다면 간단히 사용할 수 있습니다.drawRect(_:)사용자 정의 드로잉을 수행할 수 있습니다.모든 것이 잘 될 겁니다.

override func drawRect(rect: CGRect) {
    // your custom drawing code
}

drawLayer(_:inContext:)

예를 들어, 당신이 사용하고 싶은 것이 있습니다.backgroundColor사용자 지정 도면 코드:

override func drawRect(rect: CGRect) {
    let colorForCustomDrawing = self.layer.backgroundColor
    // your custom drawing code
}

당신은 ㅇㅇ을 될 입니다.backgroundColor애니메이션이 비행 중인 동안에는 올바른(즉, 현재) 값을 반환하지 않습니다.대신 최종 값(즉, 애니메이션이 완료될 때의 값)을 반환합니다.

애니메이션 중에 현재 값을 얻으려면 에 액세스해야 합니다.backgroundColorlayer 매개 변수 전달drawLayer(_:inContext:). 그리고 당신은 또한 당신에게 이끌어야 합니다.context 매개 변수.

뷰와 전달된 매개변수가 항상 같은 레이어가 아님을 아는 것이 매우 중요합니다. 후자는 부분 애니메이션이 이미 속성에 적용된 전자의 복사본일 수 있습니다.이렇게 하면 기내 애니메이션의 올바른 속성 값에 액세스할 수 있습니다.

이제 도면이 예상대로 작동합니다.

override func drawLayer(layer: CALayer, inContext context: CGContext) {
    let colorForCustomDrawing = layer.backgroundColor
    // your custom drawing code
}

하지만 두 가지 새로운 문제가 있습니다.setNeedsDisplay()과은몇지이다다이rsedl과지은몇 backgroundColor그리고.opaque더 이상 당신의 견해를 위해 일하지 않습니다.UIView은(는) 더 이상 호출 및 변경을 자체 계층으로 전달하지 않습니다.

setNeedsDisplay()만을다된다을orfgsy만p가wfodrawRect(_:)을 하든하여 커스텀 합니다. 그 기능이 실제로 어떤 일을 하는지는 상관없지만 UIKit은 그것을 사용하여 맞춤 드로잉을 하는지 아닌지를 판단합니다.

은 하지 입니다 입니다 은 하지 UIViewdrawLayer(_:inContext:)더 이상 호출되지 않습니다.

그래서 해결책은 아주 간단합니다.슈퍼클래스의요 .drawLayer(_:inContext:)빈을n을 구현합니다.drawRect(_:):

override func drawLayer(layer: CALayer, inContext context: CGContext) {
    super.drawLayer(layer, inContext: context)

    let colorForCustomDrawing = layer.backgroundColor
    // your custom drawing code
}


override func drawRect(rect: CGRect) {
    // Although we use drawLayer(_:inContext:) we still need to implement this method.
    // UIKit checks for its presence when it decides whether a call to setNeedsDisplay() is forwarded to its layer.
}

요약

사용하다drawRect(_:)애니메이션 중에 속성이 잘못된 값을 반환하는 문제가 없는 한:

override func drawRect(rect: CGRect) {
    // your custom drawing code
}

사용하다drawLayer(_:inContext:) 그리고. drawRect(_:)애니메이션화되는 동안 뷰/레이어 속성의 현재 값에 액세스해야 하는 경우:

override func drawLayer(layer: CALayer, inContext context: CGContext) {
    super.drawLayer(layer, inContext: context)

    let colorForCustomDrawing = layer.backgroundColor
    // your custom drawing code
}


override func drawRect(rect: CGRect) {
    // Although we use drawLayer(_:inContext:) we still need to implement this method.
    // UIKit checks for its presence when it decides whether a call to setNeedsDisplay() is forwarded to its layer.
}

iOS에서는 뷰와 레이어 간의 오버랩이 매우 큽니다.는 해당 로는며의을다의당e을sy의며sew는p의당,et로'fr drawLayer:inContext:◦. drawRect:그리고.drawLayer:inContext:이 경우에는 어느 정도 동등합니다.한한본은과다다ftty은,e본한,한.ndrawLayer:inContext:drawRect:, 아니면drawRect:다음의 경우에만 호출됩니다.drawLayer:inContext:서브클래스에서 구현되지 않습니다.

어떤 접근방식을 사용할지 결정하는 방법은?각각의 사용 사례가 있습니까?

그건 사실 중요하지 않아.라,합니다를 합니다.drawRect:을의 합니다.drawLayer:inContext:뷰의 일부가 아닌 사용자 정의 하위 레이어를 그려야 할 때.

Apple Documentation은 다음과 같이 말합니다. "기본 계층의 내용을 직접 설정하는 것과 같이 뷰의 내용을 제공하는 다른 방법도 있지만, drawRect: 메서드를 재정의하는 것이 가장 일반적인 기술입니다."

그러나 그것은 어떤 세부사항에도 들어가지 않으므로, 그것은 단서가 되어야 합니다: 여러분이 정말로 손을 더럽히고 싶지 않다면 그것을 하지 마세요.

UIView 계층의 대표자가 UIView를 가리킵니다.그러나 UIView는 drawRect: 구현 여부에 따라 다르게 동작합니다.예를 들어 레이어에 속성을 직접 설정하는 경우(예: 해당 배경색 또는 해당 모서리 반지름) 완전히 비어 있더라도 drawRect: 메서드가 있으면 이러한 값을 덮어씁니다(즉, super를 호출하지 않음).

언급URL : https://stackoverflow.com/questions/4979192/ios-using-uiviews-drawrect-vs-its-layers-delegate-drawlayerincontext

반응형