Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a framework gesture in AVPlayerViewController

I want the ability to change how the playback controls are presented while using the new AVPlayerViewController in AVKit. Basically, I want to overide the single finger tap gesture to do something else, and replace that gesture with a double finger tap. I am subclassing AVPlayerViewController to add this functionality.

I can add the double finger tap easily by creating a new UITapGestureRecognizer, but doing so with a single tap does nothing, as the playback controls still appear and my custom gesture method is not called. I assume because the AVPlayerViewController has a gesture with priority that is called instead.

I setup the gestures like normal...

// singleFingerTap: will never fire...
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleFingerTap:)];
singleFingerTap.numberOfTouchesRequired = 1;
singleFingerTap.delegate = self;
[self.view addGestureRecognizer:singleFingerTap];

// doubleFingerTap: will work correctly...
UITapGestureRecognizer *doubleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleFingerTap:)];
doubleFingerTap.numberOfTouchesRequired = 2;
doubleFingerTap.delegate = self;
[self.view addGestureRecognizer:doubleFingerTap];

Any thoughts on how to achieve this without accessing private properties? Is it even permitted? I know I can create my own view controller with an instance of AVPlayer and then create my own playback controls, but I'm hoping I can use the lightweight AVKit player here with a few simple modifications.

I've tried looping through the gestures in AVPlayerViewController's view and removing them, but the gestureRecognizers property was empty. Even if I could do this, I wouldn't know how to add back the gesture to display the playback controls on a double finger tap instead of the single finger tap.

Any suggestions would be much appreciated! Especially whether this is possible/allowed or not. Thanks!


EDIT: I have found a way to explicitly unblock the player's private gesture that was blocking my own gesture.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    id firstGesture = gestureRecognizer;
    id secondGesture = otherGestureRecognizer;

    if ([firstGesture isKindOfClass:[UITapGestureRecognizer class]] && [secondGesture isKindOfClass:[UITapGestureRecognizer class]]) {
        UITapGestureRecognizer *tapGesture = firstGesture;
        UITapGestureRecognizer *otherTapGesture = secondGesture;

        if (tapGesture.numberOfTapsRequired == otherTapGesture.numberOfTapsRequired && tapGesture.numberOfTouches == otherTapGesture.numberOfTouches) {
        // Disable the single tap that shows the playback controls...
            return YES;
        }
    }
    return NO;
}

This effectively prevents the playback controls from appearing on a tap, and my singleTapGesture: fires as expected. However, I now have the issue of getting the playback controls to appear on a different gesture. Is it possible to reroute the private gesture, or simulate the private gesture programmatically?

like image 279
timgcarlson Avatar asked Nov 10 '22 03:11

timgcarlson


1 Answers

Why not just check/modify the target/remove the default gesture recognizers first?

You can access them with the standard UIView's gestureRecognizers.


The gestures recognizers may be buried inside a private subview.

Another solution would be to set userInteractionEnabled to NO and add your gesture recognizers to the superview or to a "overlay" transparent view.

like image 95
Rivera Avatar answered Nov 14 '22 21:11

Rivera