I need to add a custom button to the AVPlayerViewController that will appear in both fullscreen and non-fullscreen for an app running iOS 8.
Adding a button to the AVPlayerViewController.view or the containing view will work for non-fullscreen but when the player switches to fullscreen the button is no longer visible. I have found that if I add a button to the AVPlayerViewController.ContentOverlayView then it appears in fullscreen and non-fullscreen, but then it doesn't appear that the ContentOverlayView responds to any touches so the button cannot be clicked. Does anyone know of a different place to add the button or a way to make the ContentOverlayView respond to touches?
Example Code
AVPlayerViewController *playerView = [[AVPlayerViewController alloc] init];
playerView.player = [AVPlayer playerWithURL:movieURL];
CGRect viewInsetRect = CGRectInset ([self.view bounds],
kMovieViewOffsetX,
kMovieViewOffsetY );
/* Inset the movie frame in the parent view frame. */
[[playerView view] setFrame:viewInsetRect];
[self.view addSubview: [playerView view]];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.backgroundColor = [UIColor yellowColor];
btn.frame = CGRectMake(50, 50, 200, 75);
[btn addTarget:self action:#selector(didSelectButton:) forControlEvents:UIControlEventTouchUpInside];
[btn setUserInteractionEnabled:YES];
[btn setEnabled:YES];
[playerView.contentOverlayView addSubview:btn];
I managed to get this working by adding the following to my AVPlayerViewController in IB:
An overlay view with a button inside it
Add constraints to center the button in the overlay view
Created an IBOutlet to the view (I called it 'overlay')
Created an action from the button to AVPlayerViewController that prints something so that we can see that tapping the button is working
Dragged the overlay view out of the view hierarchy and onto the top bar of the view controller (appears as a view icon in top bar of the view controller along with the exit icon etc)
and then in the code for the AVPlayerViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.overlay)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.overlay.frame = self.view.bounds
}
#IBAction func playBtnTapped(sender: AnyObject) {
println("PlayBtnTapped")
}
The button is now centered in fullscreen/normal viewing and the button works
I had the same predicament just now.
Instead of:
[playerView.contentOverlayView addSubview:btn];
use (after you add the playerView)
[self.view addSubview:btn];
This will add the button in the minimised player.
Now for the fullscreen I didn't found any other reliable method of checking if the player went fullscreen or back, so here is a a solution:
self.windowChecker = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(checkIfFullscreen) userInfo:nil repeats:YES];
and this:
-(void)checkIfFullscreen{
NSLog(#"videoBounds\n %f %f ", self.avVideoPlayer.contentOverlayView.frame.size.width,self.avVideoPlayer.contentOverlayView.frame.size.height);
if ([self playerIsFullscreen]) { // check the frame on this
for(UIWindow* tempWindow in [[UIApplication sharedApplication]windows]){
for(UIView* tempView in [tempWindow subviews]){
if ([[tempView description] rangeOfString:#"UIInputSetContainerView"].location != NSNotFound){
UIButton *testB = [[UIButton alloc] initWithFrame: CGRectMake(20, 20, 400, 400)];
testB.backgroundColor = [UIColor redColor];
[testB addTarget:self action:#selector(buttonTouch) forControlEvents:UIControlEventTouchDown];
[tempView addSubview:testB];
break;
}
}
}
}
}
I know this is a not a nice way to do it, but it is the only way I managed to add some custom UI that also receives touch events on the player.
Cheers!
Related
I am creating an iOS library. My library when initiated from AppDelegate will create a button on top of the screen.
I have created the button and it is showing up. But when I click, the target method is not evoked.
This is how I have created the button and assigned its action in the library
- (void) addLoginButton {
UIWindow *appWindow = [[[UIApplication sharedApplication] delegate] window];
UIButton *loginButton = [UIButton buttonWithType:UIButtonTypeSystem];
[loginButton setFrame:CGRectMake((appWindow.frame.size.width/2)-35, 20, 70, 20)];
[loginButton setBackgroundColor:[UIColor blueColor]];
[loginButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[loginButton setTitle:#"Login" forState:UIControlStateNormal];
[loginButton addTarget:self action:#selector(auLoginClicked) forControlEvents:UIControlEventTouchUpInside];
[appWindow addSubview:loginButton];
if([appWindow.rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navCon = (UINavigationController *)(appWindow.rootViewController);
if (!navCon.navigationBar.isHidden) {
navCon.navigationBar.layer.zPosition = 0;
}
}
loginButton.layer.zPosition = 5;
}
- (void) auLoginClicked {
NSLog(#"Hello");
}
I copied your code and have the same result.It's really strange and i am still working on it.I confirm it is the storyboard that caused the result,because i use your code in my project which does not use the storyboard,it works properly.
But please do not use loginButton.layer.zPosition = 5;It is not a proper way .
Here are some advices:
But If are you using UINavigationController Use:
[self.navigationController.view.window addSubview:aView];
If are you using UITabBarController Use:
[self.tabBarController.view.window addSubview:aView];
In AppDelegate you can directly assign a view to window. In appDelegate didFinishLaunchingWithOptions method Use:
[self.window addSubview:aView];
Hope it helps...
Instead of adding your button as a subview of window add this
then your button will get action.
[appWindow.rootViewController.view addSubview:loginButton];
If you add your view(Button) as a subview of window, then it won't be able to get events from user.That is the reason why your button not responding to event.
Debug it you will come to understand:)
If you want that to be on the top of every viewController, then check if UINavigationController is not the initialViewController then create a your own NavigationController and make it as initialContoller. It will make your button will be visible throughout the app(until the user by himself present any other VC)
UIWindow *appWindow = [UIApplication sharedApplication].keyWindow;
[appWindow addSubview:view];
You just need to fetch the keyWindow of the application and add the button as a subview. You don't have to set the zPosition
adding a button to navigation bar on first nib viewController and wanted to view this button to only on main screen not on any other screen
i have worked out on it
i made the button and added to subview of navigation bar
on every button action i have put this
- (IBAction)forth:(id)sender {
forthView *forthview = [[forthView alloc]init];
[self.navigationController pushViewController:forthview animated:YES];
btn.hidden = YES;
}
after this button hides but didnot show up when i got back to main screen
my code for viewdidload is here
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.title = #"My First View";
self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
btn = [[UIButton alloc] init];
btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(10, 10, 65, 30);
[btn setTitle:#"Show" forState:UIControlStateNormal];
[self.navigationController.navigationBar addSubview:btn];
btn.hidden = false;
}
Once you hide the button so you need to unhide it again. here is the simple code to unhide the button:
btn.hidden = No
viewDidLoadis only called the first time your view is loaded. Add an NSLog()statement if you want to test when it gets called. Every time your view appers on screen viewWillAppearis called.
So you need to show the button in viewWillAppear
It seems likely that what you really want to be doing is adding a UIBarButtonItem to your main view controller's navigationItem.leftBarButtonItem property. That way the button will have the correct appearance and show and hide as the view controller is displayed.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Show"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(onShowButtonPressed:)];
I have a view with a collection of images. If the image is clicked then I show it full screen on same screen. When the phone is rotated, I want it to autorotate only if the image is full screen, otherwise no. I have isZoomedIn that is true when a image is full screen else false.
I have implemented the method shouldAutorotate. If it is zoomed-in it returns Yes otherwise No but it doesn't work even if isZoomedIn is set corectly.
I created a demo having a button to pop-up a new view on same screen similar to your image selection on clicking.
-(IBAction)buttonClicked:(id)sender //Called when button tapped to pop-up a new view.
{
flag = YES; //Flag check for rotating new view ,i.e., YES.
newView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, self.view.frame.size.width-10, self.view.frame.size.height-10)];
[newView setBackgroundColor:[UIColor blueColor]];
closeNewViewBtn = [[UIButton alloc] initWithFrame:CGRectMake(30, 30, 100, 50)];
[closeNewViewBtn addTarget:self action:#selector(removeView) forControlEvents:UIControlEventTouchUpInside];
[closeNewViewBtn setTitle:#"Remove View" forState:UIControlStateNormal];
[closeNewViewBtn setBackgroundColor:[UIColor redColor]];
[newView addSubview:closeNewViewBtn];
[self.view addSubview:newView];
}
-(void)removeView //Called to remove view or in your case change it for removing the image or what ever you doing.
{
flag = NO;
[newView removeFromSuperview];
}
-(BOOL)shouldAutorotate //Rotation check
{
if(flag)
return YES; //Will rotate when new view is present.
else
return NO; //Will not rotate when new view is not present.
}
This will get you required needs.
I have a Tab-Bar button on a View Controller.I want when a user press that button a sub-view sides from the corner and shows the list of buttons for specified actions and on pressing tab bar button again sub-view should slide back and disappear.This sub-view should be shown on small frame of main View. How i can accomplish this task?
Add a custom action to that button.
when a user presses the button check to see if the buttons view's origin is within the bounds of your main view. if it's not, slide it in, else slide it out.
I would probably do something like that:
// Call this one on viewDidLoad
-(void)createMenuButton {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:#selector(toggleMenu) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.rightBarButtonItem = item;
}
// Make sure the menuView property was added as subview of self.view
-(void)toggleMenu {
if (CGRectContainsPoint(self.view.bounds, self.menuView.frame.origin)) {
[UIView animateWithDuration:.35
animations:^{
CGRect rect = self.menuView.frame;
rect.origin.x -= self.menuView.frame.size.width;
self.menuView.frame = rect;
}];
} else {
[UIView animateWithDuration:.35
animations:^{
CGRect rect = self.menuView.frame;
rect.origin.x += self.menuView.frame.size.width;
self.menuView.frame = rect;
}];
}
}
Hope this helps :)
i created a MPMoviePlayerViewController in my UIView (not in my UIVIewController!) like this:
self.playButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 70, 125, 100)];
[self.playButton setBackgroundImage:[UIImage imageNamed:#"video_play.png"] forState:UIControlStateNormal];
[self.playButton addTarget:self action:#selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
self.playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
self.playerViewController.moviePlayer.fullscreen = NO;
self.playerViewController.view.frame = CGRectMake(0, 0, 320, 200);
[self.playerViewController.moviePlayer prepareToPlay];
self.playerViewController.moviePlayer.shouldAutoplay = NO;
self.playerViewController.view.backgroundColor = [UIColor yellowColor];
[self addSubview:self.playerViewController.view];
[self.playerViewController.view addSubview:self.playButton];
}
- (void)buttonPressed:(id)sender{
(NSLog(#"Click"));
[self.playerViewController.moviePlayer setFullscreen:YES animated:YES];
[self.playerViewController.moviePlayer play];
}
As you can see i added a Button on the videoView, beacause this part should only be a Preview and when the user clicks on the Button the MPMoviePlayerViewController should animate to fullscreen and start playing, and when the Video is finished it should go back to the Preview View. Everything works so far, but i have two Problems:
First Problem:
Everytime i open the View my StatusBar becomes hidden and it looks like this:
So i set in my viewWillAppear and viewDidAppear of my UIViewController:
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
This works, but now the statusbar gets hidden and immediately appears again, that looks ugly, any chance to solve this Problem?
Second Problem:
When i click on the Custom Button the Video gets fullscreen and everything works correct! But when i press the DONE Button of the Video everything goes back to the Preview Screen and it looks like this: The StatusBar is hidden, the navigationbar is also broken and there is a lot of black Space above the Video, whats the Problem here?
Ok i found a solution for this Problem, its a little bit hacky but i found no other solution. In my ViewController i do:
- (void)viewDidLoad {
[super viewDidLoad];
float delay = 0.1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[UIApplication sharedApplication].statusBarHidden = NO;
});
and for the case User taps back Button i do:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[UIApplication sharedApplication].statusBarHidden = NO;
}