-drawInContext : 메소드에 복잡한 그리기 코드가있는 레이어가 있습니다. 내가해야 할 그림의 양을 최소화하려고 노력 중이므로 변경된 부분 만 업데이트하기 위해 -setNeedsDisplayInRect :를 사용하고 있습니다. 이것은 훌륭하게 작동합니다. 그러나 그래픽 시스템이 레이어를 업데이트하면 크로스 페이드를 사용하여 이전 이미지에서 새 이미지로 전환됩니다. 즉시 전환하고 싶습니다.
CATransaction을 사용하여 작업을 끄고 기간을 0으로 설정했지만 작동하지 않았습니다. 사용중인 코드는 다음과 같습니다.
[CATransaction begin];
[CATransaction setDisableActions: YES];
[self setNeedsDisplayInRect: rect];
[CATransaction commit];
CATransaction에 다른 방법이 있습니까? 대신 사용해야합니다 (kCATransactionDisableActions와 같은 -setValue : forKey : 시도).
답변
레이어에서 액션 딕셔너리를 설정 [NSNull null]
하여 적절한 키에 대한 애니메이션 으로 반환 할 수 있습니다 . 예를 들어
NSDictionary *newActions = @{
@"onOrderIn": [NSNull null],
@"onOrderOut": [NSNull null],
@"sublayers": [NSNull null],
@"contents": [NSNull null],
@"bounds": [NSNull null]
};
layer.actions = newActions;
내 레이어 중 하나에서 하위 레이어를 삽입하거나 변경할 때 페이드 인 / 아웃 애니메이션을 비활성화하고 레이어의 크기와 내용을 변경합니다. 나는 믿는다contents
업데이트 된 도면에서 크로스 페이드를 방지하기 위해 키가 찾고 열쇠 .
스위프트 버전 :
let newActions = [
"onOrderIn": NSNull(),
"onOrderOut": NSNull(),
"sublayers": NSNull(),
"contents": NSNull(),
"bounds": NSNull(),
]
답변
또한:
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
//foo
[CATransaction commit];
답변
계층의 속성을 변경하면 CA는 일반적으로 변경을 애니메이션하기 위해 암시 적 트랜잭션 개체를 만듭니다. 변경 사항에 애니메이션을 적용하지 않으려면 명시 적 트랜잭션을 만들고 kCATransactionDisableActions 속성을 true로 설정하여 암시 적 애니메이션을 비활성화 할 수 있습니다 .
목표 -C
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
// change properties here without animation
[CATransaction commit];
빠른
CATransaction.begin()
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
// change properties here without animation
CATransaction.commit()
답변
Brad Larson의 답변 외에도 사용자 정의 레이어 (사용자가 만든 레이어)의 경우 레이어를 수정하는 대신 위임 을 사용할 수 있습니다actions
사전 . 이 방법은보다 역동적이고 성능이 우수 할 수 있습니다. 또한 애니메이션 가능한 모든 키를 나열하지 않고도 모든 암시 적 애니메이션을 비활성화 할 수 있습니다.
불행히도, UIView
각각 UIView
은 이미 자체 레이어의 대리자 이므로 s를 사용자 정의 레이어 대리자로 사용할 수 없습니다 . 그러나 다음과 같은 간단한 도우미 클래스를 사용할 수 있습니다.
@interface MyLayerDelegate : NSObject
@property (nonatomic, assign) BOOL disableImplicitAnimations;
@end
@implementation MyLayerDelegate
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
if (self.disableImplicitAnimations)
return (id)[NSNull null]; // disable all implicit animations
else return nil; // allow implicit animations
// you can also test specific key names; for example, to disable bounds animation:
// if ([event isEqualToString:@"bounds"]) return (id)[NSNull null];
}
@end
사용법 (보기 내부) :
MyLayerDelegate *delegate = [[MyLayerDelegate alloc] init];
// assign to a strong property, because CALayer's "delegate" property is weak
self.myLayerDelegate = delegate;
self.myLayer = [CALayer layer];
self.myLayer.delegate = delegate;
// ...
self.myLayerDelegate.disableImplicitAnimations = YES;
self.myLayer.position = (CGPoint){.x = 10, .y = 42}; // will not animate
// ...
self.myLayerDelegate.disableImplicitAnimations = NO;
self.myLayer.position = (CGPoint){.x = 0, .y = 0}; // will animate
때때로 뷰의 컨트롤러를 뷰의 커스텀 서브 레이어의 델리게이트로 사용하는 것이 편리합니다. 이 경우 도우미 클래스가 필요하지 않으며 actionForLayer:forKey:
컨트롤러 내부에서 메서드 를 직접 구현할 수 있습니다 .
중요 사항 : UIView
기본 레이어 의 위임을 수정하지 마십시오 (예 : 암시 적 애니메이션 사용). 나쁜 일이 발생합니다.)
참고 : 레이어 다시 그리기에 애니메이션을 적용하지 않으려면 애니메이션을 비활성화하지 않는 경우가 있습니다. 실제 다시 그리기는 때때로 나중에 발생할 수 있기 때문에 [CALayer setNeedsDisplayInRect:]
호출 CATransaction
할 수 없습니다. 이 답변에 설명 된 대로 사용자 지정 속성을 사용하는 것이 좋습니다 .
답변
허용 된 답변과 유사하지만 Swift 용보다 효율적인 솔루션이 있습니다. 어떤 경우에는 값을 수정할 때마다 트랜잭션을 생성하는 것보다 성능이 문제가 될 수 있습니다. 예를 들어 60fps에서 레이어 위치를 드래그하는 일반적인 사용 사례가 언급되어 있습니다.
// Disable implicit position animation.
layer.actions = ["position": NSNull()]
레이어 동작이 해결 되는 방법 은 애플 문서를 참조하십시오 . 대리자를 구현하면 계단식에서 한 단계 더 건너 뛰지 만 대리자는 관련 UIView로 설정 해야하는 것에 대한 경고 로 인해 너무 지저분했습니다 .
편집 :을 NSNull
준수 하는 주석 작성자로 인해 업데이트 되었습니다 CAAction
.
답변
Sam의 답변과 Simon의 어려움을 기반으로 CSShapeLayer를 만든 후 델리게이트 참조를 추가하십시오.
CAShapeLayer *myLayer = [CAShapeLayer layer];
myLayer.delegate = self; // <- set delegate here, it's magic.
“m”파일의 다른 곳에 …
사용자 정의 “disableImplicitAnimations”변수 배열을 통해 전환 할 수있는 기능이없는 Sam과 기본적으로 동일합니다. “하드 와이어”접근 방식
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
// disable all implicit animations
return (id)[NSNull null];
// allow implicit animations
// return nil;
// you can also test specific key names; for example, to disable bounds animation:
// if ([event isEqualToString:@"bounds"]) return (id)[NSNull null];
}
답변
사실, 나는 정답을 찾지 못했습니다. 나를 위해 문제를 해결하는 방법은 다음과 같습니다.
- (id<CAAction>)actionForKey:(NSString *)event {
return nil;
}
그런 다음 논리를 사용하여 특정 애니메이션을 비활성화 할 수 있지만 모든 애니메이션을 제거하고 싶었으므로 nil을 반환했습니다.
