8

音楽トラックの再生の進行状況を表示し、トラック内でスクラブできるようにするカスタム スライダーを作成しました。

どちらも正常に機能しますが、ドラッグを停止してスライダーの位置を変更すると、わずかなラグ (およびジャンプした動き) が発生します - Apple Music アプリのスライダーはシームレスです。

_scrubberSlider = [[ScrubberSlider alloc] initWithFrame:CGRectMake(0, 0, 300, 30)];
_scrubberSlider.continuous = YES;
_scrubberSlider.maximumValue = 1.0f;
_scrubberSlider.minimumValue = 0.0f;
 [_scrubberSlider addTarget:self action:@selector(handleSliderMove:) forControlEvents:UIControlEventValueChanged];

- (void) handleSliderMove:(UISlider*)sender
{
    CGFloat currentPlayback = sender.value * [[_theMusicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration] floatValue];
    _theMusicPlayer.currentPlaybackTime = currentPlayback;
}

-(void) handleTrackTime
{
    if (!trackTimer)
    {
    NSNumber *playBackTime = [NSNumber numberWithFloat: _musicPlayer.currentPlaybackTime];
    trackTimer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(timeIntervalFinished:) userInfo:@{@"playbackTime" : playBackTime} repeats:YES];
    }
}

-(void) timeIntervalFinished:(NSTimer*)sender
{
     [self playbackTimeUpdated:_musicPlayer.currentPlaybackTime];
}

-(void) playbackTimeUpdated:(CGFloat)playbackTime 
{
    // Update time label
    [self updatePosition];
}

-(void) updatePosition
{
   if (!_scrubberSlider.isScrubbing)
   {
   CGFloat percent = _theMusicPlayer.currentPlaybackTime / [[_theMusicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration] floatValue];
   _scrubberSlider.value = percent;
   }
}

カスタムスライダー

@interface ScrubberSlider : UISlider

@property(nonatomic) BOOL isScrubbing;

@end

@implementation ScrubberSlider

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
    }
    return self;
}

-(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super beginTrackingWithTouch:touch withEvent:event];

    _isScrubbing = YES;

    return YES;
}

- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super endTrackingWithTouch:touch withEvent:event];

    _isScrubbing = NO;
}

@end
4

4 に答える 4

3

おそらく、あなたはこれについて間違った方法で進んでいます。トラックの時間に正確に同期しようとする代わりに (これはかなり厄介な競合状態につながります。これがまさに、ドラッグして保持してから離すのではなく、「スロー」したときにスライダーが適切に更新されない理由です)、次のようにしてください。あなたが持っているタイマーを「目盛り」として使用してください。発火率をたとえば 0.5 秒に 1 回まで下げることができます。その後、基本的に現在と同じロジックを使用します-updatePosition

-(void) updatePosition
{
   if (!_scrubberSlider.isScrubbing)
   {
       _scrubberSlider.value += .5f;
   }
}

完璧ではありませんが、NSTimer を使用して音楽トラックのタイミングに自分自身を同期させようとするよりも、はるかに効率的でシームレスです (正確な動きがうんざりして不正確になる可能性があります)。これには、スライダーの最大値がトラックの最大値と等しい必要があるため、再生を開始するメソッドの例には次のようなものが含まれます。

- (IBAction)startPlayback:(id)sender {
    //... Handle however you wish to play the track
    _scrubberSlider.maximumValue = [[_theMusicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration] floatValue];
    [self handleTrackTime];
}
于 2013-03-03T19:17:34.437 に答える
2

AVFoundationフレームワークaddPeriodicTimeObserverForInterval:queue:usingBlock:には、と非常にうまく機能するというメソッドがありAVPlayerます。非常にスムーズなスクラブを備えたAVPlayerデモがあります。の同様の方法を見つけることができませんでしたAVAudioPlayerが、おそらくAVPlayerのデモで、スムーズなスクラブを実現する方法についていくつかのアイデアが得られます。

問題の一部は、適切なタイマー間隔を見つけることです。これは、AVPlayerデモが役立つと確信しています。タイマーを使用する必要がある場合は、画面上の何かの表示を更新する場合の方が正確であるため、 CADisplayLink(ではなく)を使用することをお勧めします。NSTimer

を使用しているようですMPMusicPlayerControllerAVAudioPlayer独自のコントロールを作成している場合は、またはを使用したほうがよいでしょうAVPlayer

于 2013-03-08T18:12:30.407 に答える
1

スライダーのドラッグ時にタイマーを継続的に更新するには (急な動きをせずに)、scheduledTimerWithTimeInterval の値を最小化する必要があります。したがって、タイマーの値が次のような場合:-

timer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateElapsedTime) userInfo:nil repeats:YES];

scheduleTimerWithTimeInterval 値を最小化して、小さな変更を試みてください

timer=[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(updateElapsedTime) userInfo:nil repeats:YES];



-(void)updateElapsedTime {

     //do your stuffs here
}
于 2013-03-08T07:11:02.473 に答える