我有一个垂直的单像素 View ,我想在表示正在演奏的音符的网格上移动。根据歌曲的 BPM(每分钟节拍数),动画应该变慢或变快。音符彼此挤压在一起,宽度为 25 像素。
我现在这样做的方法是每次通过 x 个样本时将 View 向右移动 1px:
int bpm = 90;
int interval = (44100 * 60.0f / song.bpm) / 25.0f; // = 1176
// sample rate=44100 multiplied by 60 (seconds) divided by number of pixels
因此,在 BPM=90 的情况下,每播放 1176 个样本,我将 UIView 移动 1px。这工作得很好,但如果 BPM 高于 180,就会给我带来问题。此时, View 落后于播放的音乐,当 BPM 上升到 240 时, View 会偏离。
我如何使用 Views 的内置动画功能来实现这一点,并根据我在上面发布的计算来确定动画速度?我想在音乐开始播放后开始播放动画,所以我不这样做不需要逐像素手动移动它。
最佳答案
如果我没理解错的话,你想要做的是:
- 绘制静态背景图像。
- 在从左向右移动的那个上面画一条垂直线。
- 将线路的 x 位置与音频播放时间同步。
有两个问题需要解决:
- 绘画表现
- 音频同步
要获得正确的绘图性能,需要考虑两种实现方式:
- 使用 Core Animation 层和动画(比 2 更容易实现。)
- 使用 OpenGL 绘制整个 View (可能比 1 快一点,延迟少一点。)
在 OpenGL 中实现 View 的代码太多,无法作为示例发布,但这里是核心动画选项的代码:
// In the UIViewController:
- (CALayer *)markerLayer
{
static NSString *uniqueName = @"com.mydomain.MarkerLayer";
for (CALayer *layer in self.view.layer.sublayers) {
if ([layer.name isEqualToString:uniqueName])
return layer;
}
CALayer *markerLayer = [CALayer layer];
markerLayer.backgroundColor = [UIColor whiteColor].CGColor;
markerLayer.name = uniqueName;
markerLayer.anchorPoint = CGPointZero;
[self.view.layer addSublayer:markerLayer];
return markerLayer;
}
- (void)startAnimationWithDuration:(NSTimeInterval)duration
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
CALayer *markerLayer = [self markerLayer];
markerLayer.bounds = (CGRect){.size = {1, self.view.bounds.size.height}};
markerLayer.position = CGPointZero;
[CATransaction commit];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
animation.fromValue = @0.0f;
animation.toValue = [NSNumber numberWithFloat:self.view.bounds.size.width];
animation.duration = duration;
[markerLayer addAnimation:animation forKey:@"audioAnimation"];
}
音频同步在很大程度上取决于您播放它的方式,例如使用 AVFoundation 或 Core Audio。要获得精确的同步,您需要来自音频引擎的某种回调,告诉您播放现在的确切位置或播放开始的时间。
也许在您开始播放音频之前立即调用 startAnimationWithDuration:
就足够了,但这似乎有点脆弱并且取决于音频框架的延迟。
关于iphone - 将 UIView 动画速度与音频播放同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12046940/