我正在尝试为WatchKit应用录制UIView
动画。首先,我实现了没有块的函数,它返回零帧被记录。这是因为在动画完成之前调用[recorder stop]
(我认为)。所以,我添加了一个完成块。现在,self.completion
永远不会YES
。我希望完成块在动画完成时通知我。我在这里缺少什么?
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;
}
答案 0 :(得分:1)
您需要在调用动画(setBatteryLevelWithAnimation
)之前设置块属性。否则,在您设置之前尝试访问它时,它将为nil
。
另外你应该直接设置你的块属性,它会更清楚,因为那是-batteryAnaminationWithCompletion
方法的作用(顺便说一下它应拼写为"动画")
从:
[batteryView batteryAnaminationWithCompletion:^(BOOL finished){
if (finished){
[recorder stop];
}
}];
要:
[batteryView setCompletion:^(BOOL finished){
if (finished){
[recorder stop];
}
}];
答案 1 :(得分:0)
您应该在开始动画之前设置完成块(更改代码顺序)。
然后,您的块应声明为副本。
@property (nonatomic, copy) void(^completion)(BOOL finished);
然后,完全删除(错误命名的)batteryAnaminationWithCompletion方法,并使用属性:
batteryView.completion = ...
答案 2 :(得分:0)
如果我正确阅读,
当你调用 - (void)runAnimation时 它在这里调用动画块,动画块将引用目前为零的完成
[batteryView setBatteryLevelWithAnimation:YES forValue:[UIDevice currentDevice].batteryLevelInPercentage inPercent:YES];
如果你认为animationWithDuration稍后调用块2秒......这是错误的.. self.completion现在是零,动画的持续时间是2秒但是selfcompletion不是动画的,它会在前面调用..如果你想等完这个动画,你需要某种锁定。
[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);
}
}];
只需在animateWithDuration之前打印出NSLog,然后从块内部打印NSLog,看看是否引用了if(self.completion)..
答案 3 :(得分: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];
}