2013-04-14 15 views
5

Tôi đang cố gắng để animate một giới hạn UIView tùy chỉnh trong khi cũng giữ cho lớp của nó có kích thước giống như xem cha mẹ của nó. Để làm điều đó, tôi đang cố gắng tạo hiệu ứng cho các lớp bên cạnh khung nhìn cha mẹ của nó. Tôi cần lớp để gọi drawLayer: withContext AS hoạt ảnh của nó để bản vẽ tùy chỉnh của tôi sẽ thay đổi kích thước chính xác cùng với các giới hạn.Không thể có được một CALayer để cập nhật drawLayer của nó: DURING một giới hạn hoạt hình

drawLayer được gọi chính xác và vẽ chính xác trước khi tôi bắt đầu hoạt ảnh. Nhưng tôi không thể có được lớp để gọi phương thức drawLayer của nó trên M stepI bước hoạt hình giới hạn. Thay vào đó, nó chỉ gọi nó là ONCE, nhảy ngay lập tức đến "giới hạn cuối" ở khung cuối cùng của hoạt ảnh.

// self.bg is a property pointing to my custom UIView 
self.bg.layer.needsDisplayOnBoundsChange = YES; 
self.bg.layer.mask.needsDisplayOnBoundsChange = YES; 

[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{ 

    [CATransaction begin]; 
    self.bg.layer.bounds = bounds; 
    self.bg.layer.mask.bounds = bounds; 
    [CATransaction commit]; 

    self.bg.bounds = bounds; 
} completion:nil]; 

Tại sao các giới hạn báo cáo thay đổi AS hoạt ảnh (không chỉ là khung cuối cùng)? Tôi đang làm gì sai?

Trả lời

3

sức này hoặc có thể không giúp ...

Nhiều người không biết rằng Core Animation có một tính năng làm cho lạnh nhiều mà cho phép bạn xác định các thuộc tính lớp của riêng bạn trong một cách mà họ có thể được hoạt hình. Một ví dụ tôi sử dụng là cung cấp cho một lớp con CALayer một thuộc tính thickness. Khi tôi animate nó với Core Animation ...

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"thickness"]; 
ba.toValue = @10.0f; 
ba.autoreverses = YES; 
[lay addAnimation:ba forKey:nil]; 

... hiệu quả là drawInContext: hoặc drawLayer:... được gọi là liên tục trong suốt hoạt hình, cho phép tôi thay đổi liên tục cách lớp được vẽ theo của nó hiện tạithickness giá trị thuộc tính tại mỗi thời điểm (giá trị trung gian trong quá trình hoạt ảnh).

Dường như với tôi rằng có thể là loại điều bạn đang theo dõi.Nếu vậy, bạn có thể tìm thấy một ví dụ có thể tải về làm việc ở đây:

https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/ch17p498customAnimatableProperty

Thảo luận (từ cuốn sách của tôi) ở đây:

http://www.apeth.com/iOSBook/ch17.html#_making_a_property_animatable

+0

'được gọi lặp đi lặp lại trong suốt hoạt ảnh' Không tự động, không phải vậy. Đó là một giải pháp tốt, nhưng nhược điểm là bạn cần phải impliment 'needsDisplayForKey:' và để làm điều đó bạn cần phải phân lớp CALayer. Và vì có một số lớp con CALayer mà bạn có thể cần phải sử dụng (như CAGradientLayer, vv) nó có thể là một chút đau ở mông. – zakdances

+0

Vì presentationLayer chỉ trả về một bản sao tĩnh, nên câu trả lời của tôi là điều duy nhất hoạt động ngay bây giờ. Tôi đoán tôi sẽ phải thêm các thuộc tính tùy chỉnh đặc biệt cho chiều rộng và chiều cao và tạo hiệu ứng cho chúng dọc theo giới hạn. Điều đó có đúng không? – zakdances

+0

Tôi không thể chắc chắn * nó sẽ hoạt động theo cách bạn muốn, nhưng đó chắc chắn là hướng tôi nghĩ bạn nên đi vào khi tôi đưa ra gợi ý này. – matt

1

Điều này là do lớp bạn đang vẽ không giống với lớp được hiển thị trên màn hình.

Khi bạn tạo hiệu ứng một thuộc tính lớp, nó sẽ ngay lập tức được đặt thành giá trị cuối cùng trong lớp mô hình, (như bạn đã nhận thấy) và hoạt ảnh thực tế được thực hiện trong lớp trình bày.

Bạn có thể truy cập vào các lớp trình bày và xem giá trị thực tế của tài sản hoạt hình:

CALayer *presentationLayer = (CALayer *)[self.bg.layer presentationLayer]; 
... 

Vì bạn chưa cung cấp phương pháp drawLayer:withContext của bạn, nó không rõ ràng những gì bạn muốn vẽ trong phim hoạt hình, nhưng nếu bạn muốn tạo hiệu ứng thuộc tính tùy chỉnh, here is a good tutorial để thực hiện điều đó.

+0

Wow Tôi không biết về tầng trình diễn. Cảm ơn vì điều đó. Trong drawLayer của tôi, tôi chỉ có một UIBezierPath với một vài phương thức addArcWithCenter. Tôi có thể thêm nó ở đây, nhưng tôi thành thật không nghĩ rằng nó có bất kỳ loại hiệu ứng nào về việc drawLayer có được gọi hay không. – zakdances

+0

Tôi có thể sử dụng presentationLayer để kích hoạt drawLayer không? Theo các tài liệu, các phương thức presentationLayer trả về một bản sao của presentationLayer, vì vậy tôi không chắc chắn nếu quan sát các thuộc tính giới hạn là có thể ... – zakdances

+0

Có, nó trả về một bản sao của lớp trình bày, nó chỉ để đọc. Tôi không nghĩ rằng phương pháp drawLayer của bạn sẽ được gọi trong khi hoạt hình, trừ khi bạn đi với một cái gì đó như matts trả lời. Đó là lý do tại sao tôi hỏi những gì bạn đã có trong phương pháp đó, để xem nếu nó đã được animateable. – Hjalmar

1

Thứ nhất, lớp của chế độ xem lớp được sao lưu (hoặc lưu trữ) luôn được thay đổi kích thước để phù hợp với giới hạn của chế độ xem chính. Nếu bạn đặt chế độ xem là lớp ủy nhiệm thì chế độ xem sẽ nhận được drawLayer: inContext: tại mỗi khung. Tất nhiên bạn phải đảm bảo rằng nếu lớp của bạn có needsDisplayOnBoundsChange == YES.

Dưới đây là một ví dụ (trên Mac) thay đổi kích thước cửa sổ, sau đó thay đổi đường dẫn của lớp cơ bản.

// My Nib contains one view and one button. 
// The view has a MPView class and the button action is resizeWindow: 

@interface MPView() { 
    CAShapeLayer  *_hostLayer; 
    CALayer   *_outerLayer; 
    CAShapeLayer  *_innerLayer; 
} 
@end 

@implementation MPView 

- (void)awakeFromNib 
{ 
    [CATransaction begin]; 
    [CATransaction setDisableActions:YES]; 

    _hostLayer = [CAShapeLayer layer]; 
    _hostLayer.backgroundColor = [NSColor blackColor].CGColor; 
    _hostLayer.borderColor = [NSColor redColor].CGColor; 
    _hostLayer.borderWidth = 2; 
    _hostLayer.needsDisplayOnBoundsChange = YES; 
    _hostLayer.delegate = self; 
    _hostLayer.lineWidth = 4; 
    _hostLayer.strokeColor = [NSColor greenColor].CGColor; 
    _hostLayer.needsDisplayOnBoundsChange = YES; 

    self.layer = _hostLayer; 
    self.wantsLayer = YES; 

    [CATransaction commit]; 

    [self.window setFrame:CGRectMake(100, 100, 200, 200) display:YES animate:NO]; 
} 

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx 
{ 
    if (layer == _hostLayer) { 

     CGSize size = layer.bounds.size; 
     CGMutablePathRef path = CGPathCreateMutable(); 

     CGPathMoveToPoint(path, NULL, 0, 0); 
     CGPathAddLineToPoint(path, NULL, size.width, size.height); 

     _hostLayer.path = path; 

     CGPathRelease(path); 
    } 
} 

- (IBAction)resizeWindow:(id)sender 
{ 
    [self.window setFrame:CGRectMake(100, 100, 1200, 800) display:YES animate:YES]; 
} 

@end 
+0

Lớp mặc định không được đặt làm đại diện của nó theo mặc định? Hoặc tôi phải làm điều này trong init views: 'self.layer.delegate = self;' – zakdances

+0

Theo mặc định, ủy nhiệm là nil, do đó bạn phải tự thiết lập nó. – aLevelOfIndirection

+0

@yourfriendzak Chỉ có lớp mặc định. Tôi tin rằng nó thực sự ném một ngoại lệ nếu đại biểu của nó không phải là quan điểm của nó. – Sulthan

Các vấn đề liên quan