10

I have this code for my AVPlayerViewController.

UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAvPlayer)];
[self.avPlayerViewController.view addGestureRecognizer:tap];

but this is not working.. :S, I tried setting

[self.avPlayerViewController.view setUserInteractionEnabled:YES];

still no good..

The only working solution is to use UIGestureRecognizer and implement it's shouldReceiveTouch delegate and check if the av player is touched.. but the issue is, we wan't to capture the "tap release" event.. because if the av player view is just touched, it immediately executes the code and that is not what we wanted...

Please help us with this issue..

Thanks!

8 Answers8

9

The correct place for gesture handling on an AVPlayerViewController is inside the controller's contentOverlayView .

contentOverlayView is a read-only property of AVPlayerViewController. It's a view that shows up over the video, but under the controller. Just the perfect place for touch handling. You can add subviews or gesture handlers to it at load time.

The following code gives your video controller touch support in two ways, to demonstrate both the gesture recognize and UIButton approaches.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"mySegue"])
    {
        // Set things up when we're about to go the the video
        AVPlayerViewController *avpvc = segue.destinationViewController;
        AVPlayer *p = nil;
        p = [AVPlayer playerWithURL:[NSURL URLWithString:@"https://my-video"]];
        avpvc.player = p;

        // Method 1: Add a gesture recognizer to the view
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(myAction:)];
        avpvc.contentOverlayView.gestureRecognizers = @[tap];

        // Method 2: Add a button to the view
        UIButton *cov = [UIButton buttonWithType:UIButtonTypeCustom];
        [cov addTarget:self action:@selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
        cov.frame = self.view.bounds;
    }
}

(not really up for writing a Swift version at the moment, sorry. :)

TyR
  • 718
  • 4
  • 9
  • I have a AVPlayerViewController that is responsible for playing a video inside a custom UITableViewCell. The method of adding the gesture recognizer to the `contentOverlayView` doesn't seem to work. Somehow the touches are being intercepted once the player view gets added to the cell. Any thoughts on what I might be able to do to work around this issue? Thanks! – Stoph Jul 11 '19 at 15:42
  • @Stoph Did you finally found a solution? – Zigii Wong Jun 29 '21 at 10:11
  • @ZigiiWong, I had to go back and dig through my code, but I did find my solution. I ended up creating a custom `AVPlayerViewController` subclass and overriding the `- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event` method. The overridden method calls a custom delegate interface which ingests the touch event to perform whatever action I need. – Stoph Jun 29 '21 at 16:40
  • adding the recognizer to `.contentOverlayView` didn't work for me (never received the callback), but `avpvc.view.gestureRecognizers = @[tap]` did. – eddybox Nov 04 '22 at 21:36
5

This should do it. Add the recognizer to the subview of the player instead:

[videoPlayerViewController.view.subviews[0] addGestureRecognizer:tap]

This was a quick fix for complex UI and gestures look into contentOverlayView see TyR answer

Radu
  • 3,434
  • 4
  • 27
  • 38
1

Swift 4

Add a gesture recognizer to AVPlayerViewController's view:

func playVideo() {
    let playerController = AVPlayerViewController()
    playerController.player = AVPlayer(url: URL(fileURLWithPath: videoPath))
    playerController.showsPlaybackControls = false
    playerController.view.isUserInteractionEnabled = true

    let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
    swipeUp.direction = UISwipeGestureRecognizerDirection.up
    playerController.view.addGestureRecognizer(swipeUp)

    present(playerController, animated: false) {
        playerController.player?.play()
    }
}

@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
    print("swipe up")
}
Zoltan Vinkler
  • 1,207
  • 1
  • 15
  • 20
0

As far as my knowledge is concerned what you really want to is

UILongPressGestureRecognizer

Because,

UITapGestureRecognizer

Does not have any release type of event, if u add the

UILongPressGestureRecognizer

to your

avPlayerViewController

Then in

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  if ( [gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] ) {

  }
  return YES;
}

Then you can set the minimum duration of the gesture to have a better feel,

[holdGesture setMinimumPressDuration:0.01]

Then you can implement the method,

- (void)holdAction:(UILongPressGestureRecognizer *)holdRecognizer

Then check the state of the recognizer and perform desired functionality

Avinash Sharma
  • 665
  • 1
  • 7
  • 23
0

You can add transparent view on avplayerViewController and can add tapgesturerecognizer on that view. hope this will help :)

Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
0

The easy solution is add a gesture view on the same movie holder view after adding the movie player. No need to add the gesture recognizer directly to the movie player.

  [self.movieHolderView addSubview:self.moviePlayer.view];


  [self.movieHolderView addSubview:self.gestureView];
  [self.movieHolderView bringSubviewToFront:self.gestureView];

Now we can add our Gesture recognizer on the gesture view like this

self.fullScreenTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapHandler:)];
self.fullScreenTapGesture.numberOfTapsRequired = 1;
[self.gestureView addGestureRecognizer:self.fullScreenTapGesture];
Vinu David Jose
  • 2,569
  • 1
  • 21
  • 38
0

Gesture recognizer should be added differently for OS 11 and earlier OS:

Universal solution (Swift 4):

let tap = UITapGestureRecognizer(target: self, action: #selector(videoTap))

if #available(iOS 11.0, *) {
    playerVC?.contentOverlayView?.gestureRecognizers = [tap]
} else {
    playerVC?.view.subviews.first?.addGestureRecognizer(tap)
}

@objc func videoTap(_ button: UIButton) {
    print("Tapped on video")
}
Nico S.
  • 3,056
  • 1
  • 30
  • 64
-1

Or you can subclass the AVPlayerViewController and use folowwing method to

get the control : -

1.touchBegan 2.touchEnd

Make sure that you set this flag self.avPlayerContr.showsPlaybackControls = false

Hope this works for you.

Nitesh
  • 95
  • 4
  • 1
    Overriding UIControl methods is a hack. Preferred approach is with contentOverlayView (see my answer). – TyR Feb 14 '18 at 23:40