MPMoviePlayerController's view does not recognize touch

13,704

Solution 1

Actually, answer to this is simple:

  • set yourself as UIGestureRecognizer delegate
  • return YES for delegate methods:

e.g.

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture)];
tapGestureRecognizer.delegate = self;

and somewhere else in the code:

#pragma mark - gesture delegate
// this allows you to dispatch touches
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return YES;
}
// this enables you to handle multiple recognizers on single view
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}

Solution 2

MPMoviePlayerController has a subview that takes up its entire bounds, and that subview has 3 gesture recognizers on it (in iOS 4.3).

mp = [[MPMoviePlayerController alloc] initWithURL:movieURL];
mp.frame = aRectangle;

for (UIGestureRecognizer *g in ((UIView *)[mp.view.subviews objectAtIndex:0]).gestureRecognizers) {
    NSLog(@"g %@", g);
}

will output:

g <MPTapGestureRecognizer: 0x6224c30; baseClass = UIGestureRecognizer; state = Possible; cancelsTouchesInView = NO; view = <MPSwipableView 0x6416100>; target= <(action=_tapGestureRecognized:, target=<MPSwipableView 0x6416100>)>>
g <UIPinchGestureRecognizer: 0x6224710; state = Possible; cancelsTouchesInView = NO; delaysTouchesEnded = NO; view = <MPSwipableView 0x6416100>; target= <(action=_pinchGestureRecognized:, target=<MPSwipableView 0x6416100>)>>
g <MPActivityGestureRecognizer: 0x6224640; baseClass = UIGestureRecognizer; state = Possible; cancelsTouchesInView = NO; delaysTouchesEnded = NO; view = <MPSwipableView 0x6416100>; target= <(action=_activityGestureRecognized:, target=<MPSwipableView 0x6416100>)>>

So there is already a GestureRecognizer that handles a single tap, but it isn't a UITapGestureRecognizer, but an MPTapGestureRecognizer (a custom recognizer for the movie player).

If you create a generic view and add it to the movie player view hierarchy, you can add touches to it, but it blocks the touches to the movie player (so a single tap won't make the controls disappear).

e.g.

UIView *aView = [[UIView alloc] initWithFrame:mp.view.bounds];
[aView addGestureRecognizer:tapGesture];
[mp.view addSubview:aView];

This will get your tap, but you break the controls. There may still be a way to allow it to interact with the other gestures.

Solution 3

Just to share my different approach for adding a custom UISwipeGestureRecognizer to the player view without adding a custom view:

[[player.view.subviews objectAtIndex:0] addGestureRecognizer:swipeGesture];

This is to replace the conventional method of calling

[player.view addGestureRecognizer:swipeGesture];

as it only works on iPad non-fullscreen mode and on iPhone. When the player goes to fullscreen mode on iPad, the gesture does not work

Solution 4

You can use UIView UITouch event for this. Take a UIView and put MPMoviePlayerController inside that:

theMovie = [MPMoviePlayerController new];
theMovie.view.frame = CGRectMake(0, 0, 1024, 768);
[theMovie setContentURL:theURL];
[theMovie setScalingMode:MPMovieScalingModeAspectFit];
[theMovie setCurrentPlaybackTime:0.2];
[theMovie setFullscreen:YES animated:YES];
[self addSubview:theMovie.view];
[viewMovie addSubview:theMovie.view];

Use UIView touch delegate methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");
    UITouch *touch = [touches anyObject];
    startPosition = [touch locationInView:self];
    [viewMovie touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesMoved");
    UITouch *touch = [touches anyObject];
    CGPoint endPosition = [touch locationInView:self];

    if (startPosition.x < endPosition.x)
    {
        NSLog(@"Left to Right");
    }
    else
    {
        NSLog(@"Right to Left");
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{

}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{

}

Where startPosition is a CGPoint declared in .h file.

Share:
13,704
beryllium
Author by

beryllium

... vom Leben gezeichnet in den buntesten Farben. Я не живу, я слежу за собственной жизни развитием.

Updated on June 03, 2022

Comments

  • beryllium
    beryllium about 2 years

    This is my code:

    _mediaPlayer = [[MPMoviePlayerController alloc] init];
    _mediaPlayer.controlStyle = MPMovieControlStyleNone;
    _mediaPlayer.shouldAutoplay = NO;
    [_mediaPlayer.view setFrame: CGRectMake(5, 5, 600,400)];
    [playerHolder addSubview: _mediaPlayer.view];
    //
    [self prepareScreenContentToPlay];
    //
    UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleRollTap:)];
    singleFingerTap.numberOfTapsRequired = 1;
    [_mediaPlayer.view addGestureRecognizer:singleFingerTap];
    [singleFingerTap release];
    

    And action method for gesture recognizer:

    -(void)handleRollTap:(UITapGestureRecognizer*)sender{
        NSLog(@"%@", @"touch");
    }
    

    MPMoviePlayerController works fine. In addition I want to handle touch on MPMoviePlayerController view but handleRollTap never called. Why MPMoviePlayerController's view not works with UITapGestureRecognizer?


    OK. If singleFingerTap.numberOfTapsRequired = 2; then all works fine as well. But nothing for single tap..


  • devdavid
    devdavid almost 13 years
    Just realized you're setting your controlStyle to NONE already, so I guess this should work for you!
  • mdomans
    mdomans over 11 years
    Yes. Normaly a gesture recognizer assumes it should do least damage possible. But in rare cases you want to add custom touch recognizers to a view that has his own recognizers, you can set a delegate that can perform resolution when recognizers should work together. Such delegate can decide on every recognizer added to the view. It's a very usefull patern alleviating a lot of pains caused by previous approaches utilising hacking into view internals.
  • Duck
    Duck over 11 years
    simply B R I L L I A N T !!! I don't understand why your answer is was not accepted as so.
  • Toad
    Toad about 11 years
    This didn't seem to work for me. I've added a different solution for people who are still stuck
  • Ege Akpinar
    Ege Akpinar about 10 years
    Works very well. And my belief is, this has to do with the fact that MPMoviePlayerController most probably adds its own tap recogniser (to show/hide player controls for instance) so this delegate pattern allows both to work simultaneously
  • mdomans
    mdomans almost 10 years
    @EgeAkpinar exactly, MPMoviePlayerController and it views use multiple gesture recognisers
  • mdomans
    mdomans almost 10 years
    @onmyway133 that's usually the case when your delegate gets deallocated
  • Siten
    Siten over 8 years
    [[anyview.subviews objectAtIndex:0] addGestureRecognizer:swipeGesture]; Works like a champ... Bro. well done.
  • Randika Vishman
    Randika Vishman about 8 years
    trick is you giving the hint to add a swipeGesture! So it preserves the tap geusture to keep it available the Player controls! Bravo! (Y)