2015-07-13 3 views
0

Я пытаюсь записать анимацию UIView для приложения WatchKit. Во-первых, я реализовал функцию без блока, который возвращает нулевые кадры. Это было вызвано тем, что вызывается [recorder stop] до завершения анимации (я думаю). Итак, я добавил блок завершения. Теперь у него никогда не было self.completionYES. Я хочу, чтобы блок завершения уведомлял меня, когда анимация завершена. Что мне здесь не хватает?Блок всегда возвращает nil

ViewController.m

-(void)runAnimation{ 

ALBatteryView *batteryView = [[ALBatteryView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)]; 
    [self.batteryIcon addSubview:batteryView]; 
    recorder.view = _batteryIcon; 
    [recorder start]; 
    [batteryView setBatteryLevelWithAnimation:YES forValue:[UIDevice currentDevice].batteryLevelInPercentage inPercent:YES]; 
    CGFloat batteryPer = [UBattery batteryLevel]; 
    batteryPercentage.text = [NSString stringWithFormat:@"%.0f%%", batteryPer]; 
    battery = [NSString stringWithFormat:@"%.0f%%", batteryPer]; 
    [batteryView batteryAnaminationWithCompletion:^(BOOL finished){ 
    if (finished){ 
     [recorder stop]; 
    } 
    }]; 
} 

AlBatteryView.h

@interface ALBatteryView : UIView { 
UIView *batteryFill; 
} 
@property (nonatomic, strong) void(^completion)(BOOL finished); 

- (void)setBatteryLevelWithAnimation:(BOOL)isAnimated forValue:(CGFloat)batteryLevel inPercent:(BOOL)inPercent; 
- (void)reload; 
- (void)batteryAnaminationWithCompletion:(void (^)(BOOL finished))completion; 
@end 

ALBatteryView.m

- (void)setBatteryLevelWithAnimation:(BOOL)isAnimated forValue:(CGFloat)batteryLevel inPercent:(BOOL)inPercent { 

    // Declare the newWidth and save the correct battery level 
    // based on inPercent value 
    CGFloat newWidth; 
    CGFloat newBatteryLevel = (inPercent) ? batteryLevel : batteryLevel * 100; 
    // Set the new width 
    newWidth = kOnePercent * newBatteryLevel; 
    // If animated proceed with the animation 
    // else assign the value without animates 

    if (isAnimated) 
     [UIView animateWithDuration:2.0 animations:^{ 
      /* This direct assignment is possible 
      * using the UIView+ALQuickFrame category 
      * http://github.com/andrealufino/ALQuickFrame */ 
      batteryFill.width = newWidth; 
      // Set the color based on battery level 
      batteryFill.backgroundColor = [self setColorBasedOnBatteryLevel:newBatteryLevel]; 
      if (self.completion) { 
       self.completion(YES); 
      } 
     }]; 

    else 
     batteryFill.width = newWidth; 

} 
-(void)batteryAnaminationWithCompletion:(void (^)(BOOL finished))completion{ 
    self.completion = completion; 
} 
+1

почему не вы хотите использовать '[UIView animateWithDuration: 2.0 анимации:^{ } завершение: (BOOL закончен) { }]; 'и делегаты ?? – 0yeoj

ответ

0

Вы должны установить блок завершения перед запуском анимации (изменение кода заказа).

Затем ваш блок должен быть объявлен как копия.

@property (nonatomic, copy) void(^completion)(BOOL finished); 

Затем удалите метод (ошибочно названный) batteryAnaminationWithCompletion вообще, а просто использовать свойство:

batteryView.completion = ... 
+0

Комментарий от @Oyeoj отлично работает. Я не буду следовать за тобой. – iDev

1

Вам нужно установить свойство блока перед вызовом для анимации (setBatteryLevelWithAnimation). В противном случае это будет nil, когда вы попытаетесь получить к нему доступ до его установки.

Кроме того, вы должны установить свойство блока непосредственно, это будет более понятно, потому что это то, что ваш метод -batteryAnaminationWithCompletion делает (кстати это должно быть написано «Анимация») От:

[batteryView batteryAnaminationWithCompletion:^(BOOL finished){ 
    if (finished){ 
     [recorder stop]; 
    } 
    }]; 

To:

[batteryView setCompletion:^(BOOL finished){ 
    if (finished){ 
     [recorder stop]; 
    } 
    }]; 
0

Если я читаю это правильно,

Когда вы звоните - (недействительными) runAnimation он называет АНИ мация блок прямо здесь и анимация блок будет ссылающийся на завершение которых равна нулю в момент

[batteryView setBatteryLevelWithAnimation:YES forValue:[UIDevice currentDevice].batteryLevelInPercentage inPercent:YES]; 

Если вы думаете animationWithDuration вызвать блок 2 секунды позже, чем .. это неправильно .. self.completion равна нулю в момент и продолжительность анимации - 2 секунды, но self.completion не анимируется, и он вызывает прямо вверх. вам нужна какая-то блокировка, если вы хотите дождаться завершения этой анимации.

[UIView animateWithDuration:2.0 animations:^{ 
     /* This direct assignment is possible 
     * using the UIView+ALQuickFrame category 
     * http://github.com/andrealufino/ALQuickFrame */ 
     batteryFill.width = newWidth; 
     // Set the color based on battery level 
     batteryFill.backgroundColor = [self setColorBasedOnBatteryLevel:newBatteryLevel]; 
     if (self.completion) { 
        self.completion(YES); 
     } 
    }]; 

Просто распечатайте NSLog перед тем animateWithDuration и NSLog внутри блока, чтобы увидеть, когда если (self.completion) ссылаются ..

0

интерфейса является неоправданно сложным, если единственной целью анимация. Нет необходимости в блочном свойстве. Рассмотрим следующее ...

// ALBatteryView.h 
@interface ALBatteryView : UIView 

// up to you, but I'd clean up the animating interface by making a property of this class determine 
// how it handles levels in all cases as either absolute or % 
@property(assign, nonatomic) BOOL inPercent; 

// use naming style like the sdk... 
- (void)setBatteryLevel:(CGFloat)batteryLevel animated:(BOOL)animated completion:(void (^)(BOOL))completion; 

@end 

В реализации ...

// ALBatteryView.m 
@interface ALBatteryView() 

// hide the internal view property here. make it weak, and assign it after [self subView:... 
@property(weak,nonatomic) UIView *batteryFill; 

@end 

В этом методе только один анимации, используя несколько трюков в UIView анимации, вы можете сделать все, что она выглядит, как вам нужно ...

- (void)setBatteryLevel:(CGFloat)batteryLevel animated:(BOOL)animated completion:(void (^)(BOOL))completion { 

    // one trick is that UIView animation with zero duration just 
    // changes the animatable properties and calls its completion block 
    NSTimeInterval duration = (animated)? 2.0 : 0.0; 

    CGFloat newBatteryLevel = (self.inPercent)? batteryLevel : batteryLevel * 100; 
    CGFloat newWidth = kOnePercent * newBatteryLevel; 
    // don't name that color-returning method "set" color. The "set" part happens here... 
    UIColor *newColor = [self colorBasedOnBatteryLevel:newBatteryLevel]; 

    // now, the animation in just one shot, passing the block parameter 
    // which has the same signature as the UIView animation block param 
    [UIView animateWithDuration:duration animations:^{ 
     self.batteryFill.width = newWidth; 
     self.batteryFill.backgroundColor = newColor; 
    } completion:completion]; 
} 
Смежные вопросы