2012-10-26 2 views
2

좋아, 나는 여기에 여러 게시물을 기반으로 이렇게하는 방법을 알아 냈어, 그리고 그것은 잘 작동합니다. 나는 기본적으로 작은 영역을 제외한 전체 창을 마스크하는 오버레이에서 작업하고 있습니다. 이것은 내 애플 리케이션의 특정 영역에 관심을 끌기위한 것입니다. 나는 (이 내의 CALayer 하위 클래스 'drawInContext:에)과 같이 moveToPoint:addLineToPoint:에 통화의 무리를 사용하고 있습니다 :CALayer에서 부드럽게 움직이는 구멍?

.... 

// inner path (CW) 
[holePath moveToPoint:CGPointMake(x, y)]; 
[holePath addLineToPoint:CGPointMake(x + w, y)]; 
[holePath addLineToPoint:CGPointMake(x + w, y + h)]; 
[holePath addLineToPoint:CGPointMake(x, y+h)]; 

// outer path (CCW) 
[holePath moveToPoint:CGPointMake(xBounds, yBounds)]; 
[holePath addLineToPoint:CGPointMake(xBounds, yBounds + hBounds)]; 
[holePath addLineToPoint:CGPointMake(xBounds + wBounds, yBounds + hBounds)]; 
[holePath addLineToPoint:CGPointMake(xBounds + wBounds, yBounds)]; 

// put the path in the context 
CGContextBeginPath(ctx); 
CGContextMoveToPoint(ctx, 0, 0); 
CGContextAddPath(ctx, holePath.CGPath); 
CGContextClosePath(ctx); 

// set the color 
CGContextSetFillColorWithColor(ctx, self.overlayColor.CGColor); 

// draw the overlay 
CGContextDrawPath(ctx, kCGPathFillStroke); 

(holePathUIBezierPath의 인스턴스입니다.)

를 지금까지 너무 좋아. 다음 단계는 애니메이션입니다. 이를 위해

-(CABasicAnimation *)makeAnimationForKey:(NSString *)key { 
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:key]; 
    anim.fromValue = [[self presentationLayer] valueForKey:key]; 
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
    anim.duration = 0.5; 

    return anim; 
} 

및 오버라이드 actionForKey:, initWithLayer:needsDisplayForKey:을 다음과 같이 내가 (actionForKey:makeAnimationForKey:의 결과를 반환하는 방법을 만들어 (나는 또한 여기에 SO에이 기술을 발견). 자, 내가 좋은 수 "홀 레이어"는 암시적인 CAAnimations를 사용하여 애니메이션 가능하게하는 holeRect 속성을 가지고 있습니다! 불행히도, 그것은 고르지 않습니다 .2 또는 3 프레임/초 같은 것을 얻을 수 있습니다. 아마도 배경이 문제라고 생각하고 스냅 샷은 없지만 주사위는 없었습니다. 그런 다음 인스트루먼츠를 사용하여 프로필을 작성하고 큰 돼지는 여기 CGContextDrawPath()에 대한 호출임을 알게되었습니다 ..

tl; dr 내 생각에 내 질문은 다음과 같습니다. 더 빨리 다시 그릴 구멍이있는이 레이어를 만드는 더 간단한 방법이 있습니까? 내 직감은 내가 사용하고있는 경로를 단순화 할 수 있다면 길을 그리는 것이 더 가볍다는 것입니다. 아니면 마스킹을할까요? 도와주세요!

+0

심각하게? 아무도 이것에 대해 아무 말도하지 않습니까? 내 질문이 너무 길어? – samson

+0

CAShapeLayer를 사용하고 경로에 애니메이션을 적용 해보십시오. – Felix

+0

CAShapeLayer에 구멍이있을 수 있습니까? – samson

답변

2

좋아, 나는 phix23의 제안을했는데, 그것은 완전히 속임수를 썼는지! 처음에는 서브 디렉토리로 을 서브 클래 싱하고 서브 레이어로 CAShapeLayer을 추가했지만 제대로 작동하지 못했고이 시점에서 꽤 피곤해서 포기했을 때 서브 클래스를 CAShapeLayer으로 완전히 바 꾸었습니다! 나는 UIBezierPath을 돌려 자신의 방법으로 위의 코드를 사용하고,과 같이 애니메이션 :

UIBezierPath* oldPath = [self pathForHoleRect:self.holeRect]; 
UIBezierPath* newPath = [self pathForHoleRect:rectToHighlight]; 
self.holeRect = rectToHighlight; 

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; 
animation.duration = 0.5; 
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
animation.fromValue = (id)oldPath.CGPath; 
animation.toValue = (id)newPath.CGPath; 
[self.holeLayer addAnimation:animation forKey:@"animatePath"]; 
self.holeLayer.path = newPath.CGPath; 

재미있는 보조 노트는 - path 암시 애니메이션 아닙니다. 나는 그것이 합리적이라고 생각한다.

0

나는 (아직) 평판 때문에 질문에 답변을 드릴 수 없기 때문에 anwser를 게시하고 있습니다.

제 질문은 프로그래밍 방식으로 작성해야하는지 여부입니다. 관심 영역을 만들려는 경우 다른 접근법을 사용할 수 있습니다.

투명 구멍이있는 검정색 PNG 만 사용하지 않는 이유는 무엇입니까? 그런 다음 애니메이션 중에 성능 문제가 없으며 원래 구멍 크기를 잘 선택하면 어느 정도 크기가 조정될 수 있습니다. 이미지는 홀의 현재 위치에 관계없이 뷰의 모든 부분을 덮을만큼 커야합니다. 구멍 외부의 부분에는 투명도가 포함되어있어주의 영역 밖에서 음영 효과가 발생할 수 있습니다.

+0

나는 그렇게 할 수 있다고 생각한다. 단점은 일부 하이라이트 영역의 종횡비를 엉망으로 만들어야한다는 것입니다. 멋진 그림자를 갖는 것은 어려울 것입니다 (이것은 CALayer로 매우 쉽습니다). 그것은 확실히 내가 찾고있는 우아한 해결책은 아니지만 아마도 더 빨라질 것입니다 ... – samson

+0

아, 네, 이해합니다. 댓글 주셔서 감사합니다. 더 좋은 방법이있을 수 있습니다. – Masa

1

다시 그리기가 비쌉니다. 애니메이션이 아닙니다. "holeRect"에 대한 값을 설정하면 전체 레이어에 다시 그리기를 지시합니다. 이것은 일반적인 성능 최적화 속성 애니메이션과 동일하지 않습니다. 레이어가 전체 화면 크기 인 경우 모든 프레임에 레이어의 새 버전을 효과적으로 다시 만듭니다. 이것은 부드러운 애니메이션을 보장하기 위해 사과가하는 일 중 하나입니다. 가능한 한 많이 다시 그리지 않도록하고 싶습니다.

나는 가운데에 구멍이있는 레이어를 만드는 것이 좋습니다. 그리고 레이어가 중심이 어디에 있든지 상관없이 전체 스크린을 덮을만큼 큰 레이어인지 확인하십시오. 그런 다음 애니메이션은 레이어의 "위치"속성에 애니메이션을 적용해야합니다. 한 번에 ~ 30 % 만 사용되는이 거대한 계층을 갖는 것은 낭비적인 것처럼 보일 수 있지만, 모든 프레임에서 다시 그리는 것이 훨씬 덜 낭비입니다. 할 수있는 "holeRect"인터페이스를 유지하고 싶지만 "holeRect"속성이있는 레이어에는 설명 된 방식으로 애니메이션 된 하위 레이어 또는 하위 레이어가 있어야합니다 (layoutSubviews에서는 drawInContext가 아닙니다).

요약하면 레이어에서 가장 효율적인 애니메이션 중 하나 인 위치, 불투명도, 변형을 애니메이션으로 만들고 필요한 경우에만 다시 그립니다.

+0

@ wanderwaltz의 대답에 대한 내 의견보기 (그리고 지금 내 게시판에 대한 답변) 위치, 불투명도, 변환이 'CAShapeLayer' 경로 속성보다 훨씬 빠릅니까? – samson

0

예에서 직사각형 구멍을 사용합니다. 4 개의 직사각형 레이어를 사용하면 이러한 애니메이션을 구현하는 것이 더 효율적일 수 있습니다 (첨부 된 이미지 참조). 구멍 사각형 위치에 애니메이션을 적용하려면 파란색 레이어의 너비와 빨간색 레이어의 높이를 애니메이션으로 지정해야합니다. (구멍 사각형이 너비를 변경할 수 있다면 빨간색 레이어의 너비도 움직여야합니다.)

직사각형이 아닌 구멍이 필요한 경우 내부에 구멍이있는 다른 레이어를 가운데에 배치 할 수 있습니다 이 레이어의 위치 만 변경하십시오 (두 번째 이미지 참조). 이 사각형이 아닌 구멍의 크기를 조정하면 중간 레이어의 내용 만 다시 만들어 지므로 제대로 이해하면이 레이어의 크기가 화면 크기보다 약간 더 빨라야합니다.

Multilayer approach Multilayer approach, non-rectangular hole

+0

그럴듯한 소리. @ phix23에서 제안한대로'CAShapeLayer'를 사용하여 (내 솔루션을 올릴 예정 임) 문제를 해결했습니다. 이것이 그보다 더 빠를 것이라고 확신하지는 못하지만 아마도 시도해 볼 것입니다. 하나가 아닌 네 개의 레이어가 더 나빠질 것 같고 오버랩을 매끈하게 보이게 만드는 것이 어려울 수도 있습니다. – samson