prosource

에서 암시적 애니메이션 사용 안 함 -[CALayer setNeedsDisplayInRect:]

probook 2023. 6. 17. 09:27
반응형

에서 암시적 애니메이션 사용 안 함 -[CALayer setNeedsDisplayInRect:]

-drawInContext: 메서드에 복잡한 도면 코드가 있는 도면층이 있습니다.저는 제가 해야 할 도면의 양을 최소화하기 위해 -setNeedsDisplayInRect:를 사용하여 변경된 부분만 업데이트하고 있습니다.이것은 훌륭하게 작동하고 있습니다.그러나 그래픽 시스템이 계층을 업데이트하면 크로스 페이드를 사용하여 이전 이미지에서 새 이미지로 전환됩니다.저는 그것이 즉시 전환되기를 원합니다.

저는 CAT 트랜잭션을 사용하여 작업을 끄고 기간을 0으로 설정했지만 두 작업 모두 실패했습니다.제가 사용하는 코드는 다음과 같습니다.

[CATransaction begin];
[CATransaction setDisableActions: YES];
[self setNeedsDisplayInRect: rect];
[CATransaction commit];

대신 사용해야 할 CAT 트랜잭션에 다른 방법이 있습니까(-setValue:forKey:with kCATransactionDisableActions, 같은 결과).

계층에서 반환할 작업 사전을 설정하여 이 작업을 수행할 수 있습니다.[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이미 자체 계층의 대리자입니다.그러나 다음과 같은 간단한 도우미 클래스를 사용할 수 있습니다.

@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 계층 암시적 애니메이션을 - 할 수 있습니다 :) :) - 나 기 계 예 층 의 본 발 일 것 할 생 입 니 이 다 쁜 활 성 화 션 이 애 암 메 니 시 적 ▁:) ▁' 의 s ▁- ▁bad e

레이어 재드로잉을 넣지 않아도 .[CALayer setNeedsDisplayInRect:]부에전에 CATransaction왜냐하면 실제 다시 그리기는 때때로 나중에 일어날 수도 있고 아마 그럴 것이기 때문입니다. 답변에 설명된 대로 사용자 지정 속성을 사용하는 것이 좋습니다.

여기에 Swift를 제외하고는 승인된 답변과 유사한 보다 효율적인 솔루션이 있습니다.어떤 경우에는 다른 사람들이 언급했듯이 성능 문제인 값을 수정할 때마다 트랜잭션을 생성하는 것보다 더 나을 수 있습니다. 예를 들어 계층 위치를 60fps로 끌고 다니는 일반적인 사용 사례가 있습니다.

// Disable implicit position animation.
layer.actions = ["position": NSNull()]      

계층 작업을 해결하는 방법은 Apple 문서를 참조하십시오.딜러를 구현하면 캐스케이드에서 한 단계 더 건너뛸 수 있지만, 저의 경우에는 관련 UIView로 설정해야 하는 딜러에 대한 경고로 인해 너무 지저분했습니다.

편집: 해설자가 지적한 덕분에 업데이트되었습니다.NSNullCAAction.

사실, 저는 맞는 답을 찾지 못했습니다.문제를 해결하는 방법은 다음과 같습니다.

- (id<CAAction>)actionForKey:(NSString *)event {   
    return nil;   
}

그러면 그 안에 있는 어떤 논리든 특정 애니메이션을 비활성화할 수 있습니다. 하지만 저는 모든 것을 제거하고 싶었기 때문에 0을 반환했습니다.

샘의 대답과 사이먼의 어려움을 근거로...CSSapeLayer를 만든 후 대리자 참조를 추가합니다.

CAShapeLayer *myLayer = [CAShapeLayer layer];
myLayer.delegate = self; // <- set delegate here, it's magic.

"m" 파일의 다른 곳에서...

기본적으로 사용자 지정 "임시 애니메이션 사용 안 함" 변수 배열을 통해 전환하는 기능이 없는 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];

}

Swift에서 암시적 레이어 애니메이션을 사용하지 않도록 설정하려면 다음과 같이 하십시오.

CATransaction.setDisableActions(true)

내부에서 작업을 비활성화하는 더 간단한 방법을 찾았습니다.CATransaction내부적으로 전화하는 것.setValue:forKey:를해위를 .kCATransactionDisableActions키:키:

[CATransaction setDisableActions:YES];

스위프트:

CATransaction.setDisableActions(true)

MacOS가 아닌 iOS에서 하나의 암묵적 속성 애니메이션만 사용할 수 없도록 신속하게 업데이트되었습니다.

// Disable the implicit animation for changes to position
override open class func defaultAction(forKey event: String) -> CAAction? {
    if event == #keyPath(position) {
        return NSNull()
    }
    return super.defaultAction(forKey: event)
}

또 다른 예로, 이 경우 두 개의 암묵적인 애니메이션을 제거합니다.

class RepairedGradientLayer: CAGradientLayer {

    // Totally ELIMINATE idiotic implicit animations, in this example when
    // we hide or move the gradient layer

    override open class func defaultAction(forKey event: String) -> CAAction? {
        if event == #keyPath(position) {
            return NSNull()
        }
        if event == #keyPath(isHidden) {
            return NSNull()
        }
        return super.defaultAction(forKey: event)
    }
}

-drawRect() 메서드를 구현할 사용자 정의 클래스에 이 메서드를 추가합니다.당신의 필요에 맞게 코드를 변경하십시오. 저는 '불투명도'가 크로스페이드 애니메이션을 중지하는 방법을 사용했습니다.

-(id<CAAction>) actionForLayer:(CALayer *)layer forKey:(NSString *)key
{
    NSLog(@"key: %@", key);
    if([key isEqualToString:@"opacity"])
    {
        return (id<CAAction>)[NSNull null];
    }

    return [super actionForLayer:layer forKey:key];
}

매우 신속한(그러나 분명히 진부한) 수정이 필요한 경우에는 그냥 할 가치가 있을 수 있습니다(Swift).

let layer = CALayer()

// set other properties
// ...

layer.speed = 999

iOS 7부터는 다음과 같은 편리한 방법이 있습니다.

[UIView performWithoutAnimation:^{
    // apply changes
}];

CATextLayer의 문자열 속성을 변경할 때 성가신(흐림) 애니메이션을 비활성화하려면 다음 작업을 수행합니다.

class CANullAction: CAAction {
    private static let CA_ANIMATION_CONTENTS = "contents"

    @objc
    func runActionForKey(event: String, object anObject: AnyObject, arguments dict: [NSObject : AnyObject]?) {
        // Do nothing.
    }
}

그런 다음 이렇게 사용합니다(CATextLayer를 올바르게 설정하는 것을 잊지 마십시오(예: 올바른 글꼴 등).

caTextLayer.actions = [CANullAction.CA_ANIMATION_CONTENTS: CANullAction()]

CATextLayer의 전체 설정은 다음과 같습니다.

private let systemFont16 = UIFont.systemFontOfSize(16.0)

caTextLayer = CATextLayer()
caTextLayer.foregroundColor = UIColor.blackColor().CGColor
caTextLayer.font = CGFontCreateWithFontName(systemFont16.fontName)
caTextLayer.fontSize = systemFont16.pointSize
caTextLayer.alignmentMode = kCAAlignmentCenter
caTextLayer.drawsAsynchronously = false
caTextLayer.actions = [CANullAction.CA_ANIMATION_CONTENTS: CANullAction()]
caTextLayer.contentsScale = UIScreen.mainScreen().scale
caTextLayer.frame = CGRectMake(playbackTimeImage.layer.bounds.origin.x, ((playbackTimeImage.layer.bounds.height - playbackTimeLayer.fontSize) / 2), playbackTimeImage.layer.bounds.width, playbackTimeLayer.fontSize * 1.2)

uiImageTarget.layer.addSublayer(caTextLayer)
caTextLayer.string = "The text you want to display"

이제 caTextLayer.string을 원하는 만큼 업데이트할 수 있습니다=)

이것에서 영감을 받았고, 이 대답을 받았습니다.

이거 먹어봐요.

let layer = CALayer()
layer.delegate = hoo // Same lifecycle UIView instance.

경고

UITableView 인스턴스의 대리자를 설정하는 경우 충돌이 발생할 수 있습니다.(재귀적으로 호출된 보기의 히트 테스트를 스크롤할 수 있습니다.

언급URL : https://stackoverflow.com/questions/2244147/disabling-implicit-animations-in-calayer-setneedsdisplayinrect

반응형