考慮在時間上重疊的兩個變化是這樣的:
|---- change x ---|
|---- change y ----|
如果兩個間隔是任意的,並且重疊的,所述可表示由三個動畫:一個改變單獨一個維度,一個改變兩個維度一起,另一個分別改變一個維度。
你可以看到,有很多方法可以指定這個,但讓我們嘗試一個簡單的方法。爲了避免複合比例的算術,我們指定一個尺寸,一個像素變化和一個持續時間。例如...
@[ @{@"dimension":@"width", @"delta":@10, @"duration":0.2},
@{@"dimension":@"both", @"delta":@40, @"duration":0.8},
@{@"dimension":@"width", @"delta":@10, @"duration":0.2} ]
...表示跨越較短的高度變化時寬度變化較大。你可以看到這是一個非常完整的語言,可以完成你想要的任務。
我們需要一個連續執行更改的動畫方法。一個簡單的方法就是將這組操作視爲一個待辦事項列表。遞歸算法說:要做的事情列出來,做第一個,然後做休息....
- (void)animateView:(UIView *)view actions:(NSArray *)actions completion:(void (^)(BOOL))completion {
if (actions.count == 0) return completion(YES);
NSDictionary *action = actions[0];
NSArray *remainingActions = [actions subarrayWithRange:NSMakeRange(1, actions.count-1)];
[self animateView:view action:action completion:^(BOOL finished) {
[self animateView:view actions:remainingActions completion:completion];
}];
}
對於動畫,你可能想使用線性時序曲線中間的動畫,儘管我可以看到你變得更加細緻,並在列表的開始和結束處改變時序曲線。
- (void)animateView:(UIView *)view action:(NSDictionary *)action completion:(void (^)(BOOL))completion {
NSString *dimension = action[@"dimension"];
CGFloat delta = [action[@"delta"] floatValue];
NSTimeInterval duration = [action[@"duration"] floatValue];
CGRect frame = view.frame;
if ([dimension isEqualToString:@"width"]) {
frame = CGRectInset(frame, -delta, 0);
} else if ([dimension isEqualToString:@"height"]) {
frame = CGRectInset(frame, 0, -delta);
} else {
frame = CGRectInset(frame, -delta, -delta);
}
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
view.frame = frame;
} completion:completion];
}
如果字典的數組是太笨拙指定(這是相當普遍的),你可以添加在上面一些方便的方法是提供一些簡單的方案給調用者,並建立更廣泛的代表性的陣列。
感謝您的深度響應 - 我一直在干涉這樣的理論,但在執行準確時遇到了一些麻煩。希望這會最終引導我走向正確的方向。 –
如果是我,我會把它放在自己的小項目中(或者至少在你當前的項目中它是自己的視圖控制器),並且只是用組合來混淆。我一開始使用很長的時間,所以我可以看到什麼是哈克。 – danh