2011-09-27 39 views
16

我想知道如何動畫CALayer的界限,所以,在每個界限的變化,層調用drawInContext:。我已經試過2種以下方法,對我的CALayer的子類:動畫CALayer的界限瓦特/重繪

  • 設置needsDisplayOnBoundsChangeYES
  • bounds關鍵

無論工作返回YES爲+ (BOOL)needsDisplayForKey:(NSString*)key。 CALayer似乎決定使用該圖層的原始內容,並根據contentsGravity(我認爲這是爲了提高性能)對它們進行縮放。他們是這樣做的解決方法還是我錯過了明顯的東西?

編輯:而且,順便說一句,我發現我的自定義CALayer子不叫initWithLayer:創建presentationLayer - 怪異。

由於提前, 山姆

+0

另一件行不通的事:子類化和重載'setFrame','setBounds'和'setPosition'。在動畫過程中不會調用它們。 –

+0

我不太瞭解你。你想要做什麼動畫?只是CALayer的界限或別的什麼?限制動畫是非常簡單的任務,框架動畫 - 更復雜。 – beryllium

+0

想象一下,您的圖層包含類似具有複雜但大小獨立的邊框圖形的按鈕。如果將動畫設置爲寬度的兩倍,則它將使用位圖縮放進行動畫製作,在整個動畫中變得拉伸並像素化,即使您擁有「needsDisplayOnBoundsChange」YES。只有最後一幀才能用'drawInContext:'正確渲染。 –

回答

1

我不知道該設置viewFlags將是有效的。第二種解決方案絕對不行:

默認實現返回NO。對於由超類定義的屬性,子類應該*調用超級 。 (例如,*不要試圖 返回YES通過的CALayer實現的屬性,*做法將 無法預料的結果。)

您需要的視圖的內容模式設置爲UIViewContentModeRedraw:

UIViewContentModeRedraw, //redraw on bounds change (calls -setNeedsDisplay) 

結賬Apple's documentation on providing content with CALayer's。他們建議使用CALayer的委託屬性而不是子類,這可能比您現在嘗試的要容易得多。

+0

UIViewContentModeRedraw不會在動畫的每個步驟中重繪圖層的內容。 – titaniumdecoy

+0

真的嗎?嗯......你知道在動畫過程中是否調用CALayerDelegate方法嗎? –

+0

除非你使用我在我的答案中鏈接的技巧(這是覆蓋CALayer的'+ needsDisplayForKey:'方法) – titaniumdecoy

6

您可以使用technique outlined here:覆蓋CALayer的+needsDisplayForKey:方法,它會在動畫的每一步重繪其內容。

+0

這是一個很好的答案。在我們點擊之前提供一些關於鏈接的更多信息。 –

+0

儘管奇怪的是,CALayer不會顯示這些重繪的結果,但會繼續提前生成的拉伸內容,這種方法確實會爲每幀都調用重繪方法。不過,這是一個重大的進步。 –

+0

@AlexanderLjungberg:這種方法應該在動畫的每一步都重新繪製內容。我創建了一個測試項目來確認它的工作原理。我不確定可能會導致圖層無法重​​新顯示。 – titaniumdecoy

-2

這是你的自定義類:

@implementation MyLayer 

-(id)init 
{ 
    self = [super init]; 
    if (self != nil) 
     self.actions = [NSDictionary dictionaryWithObjectsAndKeys: 
         [NSNull null], @"bounds", 
         nil]; 
    return self; 
} 

-(void)drawInContext:(CGContextRef)context 
{ 
    CGContextSetRGBFillColor(context, 
          drand48(), 
          drand48(), 
          drand48(), 
          1); 
    CGContextFillRect(context, 
         CGContextGetClipBoundingBox(context)); 
} 

+(BOOL)needsDisplayForKey:(NSString*)key 
{ 
    if ([key isEqualToString:@"bounds"]) 
     return YES; 
    return [super needsDisplayForKey:key]; 
} 

@end 

這些補充的Xcode 4.2默認的模板:

-(BOOL)application:(UIApplication*)application 
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
     // Override point for customization after application launch. 
    self.window.backgroundColor = [UIColor whiteColor]; 
    [self.window makeKeyAndVisible]; 

     // create and add layer 
    MyLayer *layer = [MyLayer layer]; 
    [self.window.layer addSublayer:layer]; 
    [self performSelector:@selector(changeBounds:) 
       withObject:layer]; 

    return YES; 
} 

-(void)changeBounds:(MyLayer*)layer 
{ 
     // change bounds 
    layer.bounds = CGRectMake(0, 0, 
           drand48() * CGRectGetWidth(self.window.bounds), 
           drand48() * CGRectGetHeight(self.window.bounds)); 

     // call "when idle" 
    [self performSelector:@selector(changeBounds:) 
       withObject:layer 
       afterDelay:0]; 
} 

-----------------編輯:

好吧......這不是你要求的:)對不起:

-----------------編輯(2):

爲什麼你會需要這樣的東西嗎? (void)display可能會被使用,但文件說,它是在那裏設置self.contents ...

+0

這不起作用:+ needsDisplayForKey不強制重繪「邊界」 –

0

我不知道這是否完全符合您的問題的解決方案,但能夠得到這個工作。

我首先將我的內容圖像預先畫成CGImageRef

然後我覆蓋了我的圖層的-display方法INSTEAD的-drawInContext:。在其中,我將contents設置爲預渲染的CGImage,並且工作正常。

最後,您的圖層還需要將默認contentsGravity更改爲類似@"left"的內容,以避免縮放內容圖像。

我遇到的問題是,傳遞給-drawInContext:的上下文是圖層的起始大小,而不是最終的動畫後大小。 (你可以用CGBitmapContextGetWidthCGBitmapContextGetHeight方法檢查。)

我的方法仍然只能調用一次,整個動畫,而是直接與-display方法設置圖層的內容可以讓你通過圖片比可視範圍更大。 drawInContext:方法不允許這樣做,因爲你不能在CGContext上下文的範圍之外繪製。

欲瞭解更多有關不同圖層繪製方法之間的差異,看到http://www.apeth.com/iOSBook/ch16.html

0

我遇到了同樣的問題最近。這是我發現:

有一個小竅門,你可以做到這一點,那就是動畫界的卷影副本,如:

var shadowBounds: CGRect { 
    get { return bounds } 
    set { bounds = newValue} 
} 

然後覆蓋的CALayer的+ needsDisplayForKey :.

但是,這可能不是你想要做的,如果你的繪圖依賴於邊界。正如您已經注意到的,核心動畫只是簡單地將圖層的內容縮放爲動畫邊界。即使您執行了上述技巧,情況也是如此,即,即使動畫期間邊界發生變化,內容也會縮放。結果是你的圖畫動畫看起來不一致。

如何解決?由於內容是縮放的,因此可以通過反轉縮放來計算自定義變量的值,以確定最終但縮放後的內容的繪製看起來與原始縮放內容相同,然後將fromValues設置爲這些值, toValues到他們以前的價值觀,在界限的同時爲他們製作動畫。如果要更改最終值,請將toValues設置爲這些最終值。您必須動畫至少一個自定義變量以導致重繪。