iOS: Using UIView's 'drawRect:' vs. its layer's delegate 'drawLayer:inContext:'
나는 하위 클래스인 수업이 있습니다.UIView
. 뷰 내부에 있는 것을 구현하여 그릴 수도 있습니다.drawRect
방법 또는 구현을 통해drawLayer:inContext:
이것은 의 대리인 방법입니다.CALayer
.
I have two questions:
- How to decide which approach to use? Is there a use case for each one?
구현할 경우
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:
당신이 구현할 때 호출된 적이 없습니다.drawLayer:inContext:
. 이것은 또한 당신이 어떠한 것도 실행해서는 안 되는 이유이기도 합니다.CALayer
사용자 정의에서 대리인 메서드 그리기UIView
아류의또한 다른 도면층에 대한 도면 대리인을 볼 수 없습니다.그것은 모든 종류의 익살스러움을 야기할 것입니다.
구현하는 경우drawLayer:inContext:
당신이 접속해야 하기 때문에CGContextRef
, 당신은 당신의 안에서 그것을 얻을 수 있습니다.drawRect:
전화로UIGraphicsGetCurrentContext()
.
drawRect
반드시 필요한 경우에만 실행해야 합니다.기본 구현:drawRect
보기의 렌더링을 지능적으로 캐싱하는 것과 같은 여러 가지 스마트 최적화 기능이 포함되어 있습니다.우선순위를 정하는 것은 모든 최적화를 우회하는 것입니다.큰일이네요.레이어 드로잉 방법을 효과적으로 사용하면 거의 항상 커스텀보다 성능이 뛰어납니다.drawRect
. 애플은 a를 사용합니다.UIView
의 대표로서CALayer
모든 UIView가 해당 계층의 대리인인 경우가 많습니다.UI 내부 레이어 도면을 사용자 정의하는 방법을 확인할 수 있습니다. (현재) 줌잉을 포함한 여러 Apple 샘플에서 보기PDF 뷰어.
를 하는 하는의 사용 중drawRect
일반적으로, 적어도 2002/2003년 이후로 권장되지 않는 관행입니다, IIRC.그 길을 가야 할 마땅한 이유가 별로 남아 있지 않습니다.
기술 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
애니메이션이 비행 중인 동안에는 올바른(즉, 현재) 값을 반환하지 않습니다.대신 최종 값(즉, 애니메이션이 완료될 때의 값)을 반환합니다.
애니메이션 중에 현재 값을 얻으려면 에 액세스해야 합니다.backgroundColor
layer
매개 변수 전달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은 그것을 사용하여 맞춤 드로잉을 하는지 아닌지를 판단합니다.
은 하지 입니다 입니다 은 하지 UIView
인 drawLayer(_: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
'programing' 카테고리의 다른 글
워드프레스의 이미지에 카테고리 할당 (0) | 2023.09.14 |
---|---|
-webkit-transform을 사용하면 위치가 고정되지 않습니다. (0) | 2023.09.14 |
템플릿 디렉터리 Timber/Twig 가져오기 (0) | 2023.09.14 |
동적 데이터를 표시하기 위한 for loop 만들기 (0) | 2023.09.14 |
도커 컨테이너가 있는 MariaDB Galera 클러스터 - 노드가 클러스터에 가입하지 않음 (0) | 2023.09.14 |