2012-10-26 111 views
2

好吧,我想出瞭如何根據SO上的各種帖子來做到這一點,它的工作原理非常棒。我正在研究一個疊加層,它將基本上掩蓋整個窗口,除了一個小區域。這是爲了吸引關注我的應用程序的特定領域。我使用的是一堆電話來moveToPoint:addLineToPoint:像這樣(這是我的CALayer的子類drawInContext:):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:結果。現在,我得到一個不錯的「hole layer」,它有一個屬性holeRect,它可以使用隱式CAAnimations進行動畫處理!不幸的是,它是SUPER波濤洶涌,我得到了像每秒2或3幀的東西,我認爲問題可能是背景,並試圖用快照,但沒有骰子,然後,我使用儀器進行配置,並發現這裏的巨大生豬是撥打CGContextDrawPath()

tl; dr我想我的問題歸結爲這個:是否有一種更簡單的方法來創建這個圖層,並在其中創建一個更快的圖層?我的直覺是,如果我可以簡化我使用的路徑,繪製路徑會更輕。或者可能掩蓋?請幫忙!

+0

認真嗎?沒有人對此有何評論?我的問題太久了? – samson

+0

嘗試使用CAShapeLayer併爲路徑設置動畫。 – Felix

+0

CAShapeLayer可以在其中有洞嗎? – samson

回答

2

好吧,我試過phix23的建議,並且它完全沒有的伎倆!起初,我的子類CALayer並增加了一個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

在你的例子中你使用了一個矩形孔。如果您使用四個矩形圖層,則實現此類動畫可能會更有效(請參閱附加圖像)。要爲空白矩形位置設置動畫,您必須爲藍色圖層的寬度和紅色圖層的高度設置動畫。 (如果孔矩形可以改變寬度,那麼紅色層的寬度也必須是動畫的)

如果你需要一個非矩形孔,你可以在這些孔的中間放置另一個層,孔內有孔並只改變這一層的位置(見第二幅圖)。調整此非矩形孔的大小將導致只重新創建中間層的內容,因此,如果我理解正確,它應該比原始情況下的圖層的大小更快。

Multilayer approach Multilayer approach, non-rectangular hole

+0

聽起來似乎合理。我已經通過@ phix23建議使用'CAShapeLayer'解決了這個問題(即將發佈我的解決方案)。不知道這會比這更快,但也許我會嘗試一下。看起來像四層而不是一層會變得更糟,並且可能很難使重疊看起來無縫? – samson