I am trying to give up MPMoviePlayerController and switch to AVPlayer but facing problem on 'AVPlayer(Layer) Full Screen animation'.
Project Source Code: http://www.kevin-and-idea.com/avplayer.zip
Goal: Currently, AVPlayer(Layer) is part of the elements on ViewController. The play is need to be able to switch between 'Small' and full screen and when it full screen, it need to be above (cover) statue bar and navigation bar. Also, the player need to be rotate-able depends on Device Orientation
Problem: Don't know how to 'take out' the AVPlayerLayer and 'Cover' the whole screen including statue bar & navigation bar.
Currently: I set UINavigationBar hide and status bar hide to archive but this is not the goal and rotate without issue
THANK YOU SO MUCH!!!
p.s. Click the info icon to switch to full screen
https://c1.staticflickr.com/1/388/18237765479_7d3c292449_z.jpg
Code
- (IBAction)goFullScreen:(id)sender {
[UIView animateWithDuration:0.25
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
if (topSpaceConstraints.priority == 999) {
videoContainerSizeRatioConstraints.priority = 250;
[[UIApplication sharedApplication] setStatusBarHidden:YES];
[self.navigationController setNavigationBarHidden:YES];
topSpaceConstraints.priority = 250;
} else {
videoContainerSizeRatioConstraints.priority = 999;
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[self.navigationController setNavigationBarHidden:NO];
topSpaceConstraints.priority = 999;
}
[self.view layoutIfNeeded];
}
completion:nil];
}
You have two options (maybe more):
You create a view that is higher in the view hierarchy than your navigation controller view therefore you can just put something that is 'above'. Probably this would be the most visually appealing one and I'm sure most professional apps use this.
The other option you have is just to hide the navigationbar when someone pushes the fullscreen button.
UPDATE:
Maybe a 'better' way for options 1:
I looked at prev. project of mine and maybe you want to use this:
Create a new window to contain your avplayer.
Subclass UIView and implemnt a 'show' method like this:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.alpha = 0;
self.window.windowLevel = UIWindowLevelAlert;
self.window.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
[self.window addSubview:self];
[self.window addSubview:self];
[self.window makeKeyAndVisible];
[UIView animateKeyframesWithDuration:0.3 delay:0 options:UIViewKeyframeAnimationOptionBeginFromCurrentState animations:^{
[UIView addKeyframeWithRelativeStartTime:0. relativeDuration:0.7 animations:^{
// PROBABLY MORE ANIMATION HERE...
self.alpha = 1;
}];
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1 animations:^{
self.window.backgroundColor = [UIColor colorWithWhite:0.0f alpha:self.targetDimmDensity];
}];
} completion:^(BOOL finished) {
}];
The self.window is a new #property (nonatomic, strong) UIWindow *window; I created!
Related
In my application I want to disable screen shots function for IOS in React-native.
Please suggest me any working package or any native code which can disable screen shots in IOS.
this is one of the solutions by the library react native prevent screenshot:, check out the link rn-screenshot
Overlay screen by added 2 two into appDelegate.m
- (void)applicationWillResignActive:(UIApplication *)application {
// fill screen with our own colour
UIView *colourView = [[UIView alloc]initWithFrame:self.window.frame];
colourView.backgroundColor = [UIColor whiteColor];
colourView.tag = 1234;
colourView.alpha = 0;
[self.window addSubview:colourView];
[self.window bringSubviewToFront:colourView];
// fade in the view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 1;
}];
}
- (void)applicationDidBecomeActive:(UIApplication \*)application {
// grab a reference to our coloured view
UIView \*colourView = [self.window viewWithTag:1234];
// fade away colour view from main view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[colourView removeFromSuperview];
}];
}
I am creating Animated splash screen in "didFinishLaunchingWithOptions" method. Animation Splash screen duration is 2 seconds. After two seconds i am hiding the Animated Splash screen. When Animated screen appears i want to hide the status bar and when animated screen disappear i want to show the status bar.
how to do that?
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Here i am creating Animated Splash screen
***** Here i want to hide Status bar*******
splashView =[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 320, 580)];
splashView.backgroundColor =[UIColor whiteColor];
[self.window addSubview:splashView];
logoView = [[UIImageView alloc] initWithFrame:CGRectMake(logoX,0, 225, 25)];
logoView.image = [UIImage imageNamed:#"logoImage"];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:window cache:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(startupAnimationDone:finished:context:)];
splashView.alpha = 1.0;
logoView.frame = CGRectMake(logoX, logoY, 225, 25);
[window addSubview:logoView];
[window bringSubviewToFront:logoView];
[UIView commitAnimations];
// Hiding Animated splash screen After 2 second Here
- (void)startupAnimationDone:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
************* Here i want to show Status bar Again ***************
[splashView removeFromSuperview];
[logoView removeFromSuperview];
}
You go into ProjectSettings -> General. There is an option Status Bar Style.
EDIT
Use block. They provide really simple syntax for animations.
[UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
//your animation code here
//all changes made here to frame, bounds, alpha etc. are animated
} completion:^(BOOL finished) {
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
//this is called after animation finishes
}];
Add the following entries in your plist file:
"Status bar is initially hidden" = Yes: Hides the status bar at application start and in the splash screen
"View controller-based status bar appearance" = No: Prevents that the view controller classes show the status bar
You can create a category for UIViewController
#implementation UIViewController (HideStatusBar)
-(BOOL)prefersStatusBarHidden
{
return YES;
}
OK, I get the concept of adding a UIImageView as soon as the app launches, and animating it out to fake the splash animation. However, the status bar interferes.
I need a UIImageView on top of everything, including the status bar, and while it fades away, the app is shown with the status bar. Hence, settings the Status bar initially hidden, then animating it in is not a viable option.
What you require is a second UIWindow with a windowLevel of UIWindowLevelStatusBar or higher. You would create two UIWindow objects in your application delegate, one with your regular view hierarchy, the other with the image, and animate the second to fade out (or however else you need to animate). Both windows should be visible, with the splash window being on top.
This approach is complicated, as you might have problems with rotation, depending on your regular view hierarchy. We've done this in our software, and it works well.
EDIT:
Adapted Solution (window approach, very simple):
UIImageView* splashView = [[UIImageView alloc] initWithImage:[UIImage imageWithBaseName:#"Default"]];
[splashView sizeToFit];
UIViewController* tmpVC = [UIViewController new];
[tmpVC.view setFrame:splashView.bounds];
[tmpVC.view addSubview:splashView];
// just by instantiating a UIWindow, it is automatically added to the app.
UIWindow *keyWin = [UIApplication sharedApplication].keyWindow;
UIWindow *hudWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0.0f, -20.0f, keyWin.frame.size.width, keyWin.frame.size.height)];
[hudWindow setBackgroundColor:[UIColor clearColor]];
[hudWindow setRootViewController:tmpVC];
[hudWindow setAlpha: 1.0];
[hudWindow setWindowLevel:UIWindowLevelStatusBar+1];
[hudWindow setHidden:NO];
_hudWin = hudWindow;
[UIView animateWithDuration:2.3f animations:^{
[_hudWin setAlpha:0.f];
} completion:^(BOOL finished) {
[_hudWin removeFromSuperview];
_hudWin = nil;
}];
Finally, credit goes to this guy.
A more simple approach would be to launch your application with the status bar hidden, have the view you would like to animate on the top of the view hierarchy, and after the animation is finished, display the status bar using [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide]
You can add a subview to the App's UIWindow. Set the Y coordinate of the UIImageView's frame to -20 pixels in order to handle the status bar.
Add the Default PNG image to your window and tag it:
static const NSInteger kCSSplashScreenTag = 420; // pick any number!
UIImageView *splashImageView;
// Careful, this wont work for iPad!
if ( [[UIScreen mainScreen] bounds].size.height > 480.0f ) // not best practice, but works for detecting iPhone5.
{
splashImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default-568h"]];
}
else
{
splashImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default"]];
}
splashImageView.frame = CGRectMake(0.0f, -20.0f, splashImageView.image.size.width, splashImageView.image.size.height);
splashImageView.tag = kCSSplashScreenTag;
[self.window addSubview:splashImageView];
[splashImageView release];
[self _fadeOutSplaceImageView];
Then fade it out
- (void)_fadeOutSplashImageView
{
UIView *splashview = [self.window viewWithTag:kCSSplashScreenTag];
if ( splashview != nil )
{
[UIView animateWithDuration:0.5
delay:0.0
options:0
animations:^{
splashview.alpha = 0.0f;
}
completion:^(BOOL finished) {
[splashview removeFromSuperview];
}];
}
}
It's my first post on stackoverflow. I'm a iOS developer newbie and I'm not a native English speaker, so I will do my best to explain my problem.
Problem:
I have added two views to my AppDelegate window and I want to flip from one to the other using:
UIView transitionFromView:toView:
The first view (MainScreenView) has its own ViewController. On the MainScreenView .xib file I have a button with an action that calls the method "goShow" implemented in my AppDelegate. In that method I use UIView transitionFromView:toView: to transition to the second view. So far everything is working fine.
My second view (a scrollview) is declared programmatically in my AppDelegate and has a bunch of pictures inside it (picturesViewController) and on top of those, has a UIPinchGestureRecognizer.
I'm using a gesture recognizer to flip back to my MainScreenView. That is where the problem is. When I do a pinch gesture on the scrollview the MainScreenView.view appears immediately, before the animation, so the flip animation looks wrong.
The code I'm using is:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
mainScreen = [[MainScreenViewController alloc] initWithNibName:#"MainScreenViewController" bundle: [NSBundle mainBundle]];
CGRect frame = self.window.bounds;
int pageCount = 10;
scrollView = [[UIScrollView alloc] initWithFrame:frame];
scrollView.contentSize = CGSizeMake(320*pageCount, 480);
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = FALSE;
scrollView.showsVerticalScrollIndicator = FALSE;
scrollView.delegate = self;
[...] 'While' adding pictures to de scrollView
UIPinchGestureRecognizer *twoFingerPinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(goBackToMain)] autorelease];
[scrollView addGestureRecognizer:twoFingerPinch];
[self.window addSubview: scrollView];
[scrollView setHidden:TRUE];
[self.window addSubview: mainScreen.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void) goShow{
[UIView transitionFromView:mainScreen.view
toView:scrollView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView commitAnimations];
}
-(void) goBackToMain {
[UIView transitionFromView:scrollView
toView:mainScreen.view
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView commitAnimations];
}
I'm using show/hide views instead of addSubview/removeFromSuperView because I tried the add and remove and got an app crash in the pinch gesture, exactly in same step that is failing the animation. Probably it is the same error, but I'm unable to find the reason for this. Any help would be appreciated.
Thanks.
Ok. With Adrian's help, here's the UIPinchGesture code that solved my problem:
[...]
UIPinchGestureRecognizer *twoFingerPinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(goBackToMain:)] autorelease];
[scrollView addGestureRecognizer:twoFingerPinch];
-(void)goBackToMain:(UIPinchGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded)
{
[UIView transitionFromView:scrollView
toView:mainScreen.view
duration:0.4
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:nil];
[UIView commitAnimations];
}
First, you cannot mix the old method beginAnimation commitAnimation combination with the new block method transitionFromView.
Second, when using block method animation, make sure you use a container (probably a UIView) that will be the parent of the two views you want to switch. Without the container you will be animating the whole view instead. Make sure the container have the same size as the subviews that will switch.
Example:
[container addSubView:frontView];
[container addSubView:backView];
[self.view addSubView:container];
[UIView transitionFromView:backView toView:frontView duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
Read more about animations in iOS.
In your example you forgot [UIView beginAnimations].
I'd like to show and hide the statusBar and the navigationBar simultaneously using a slide effect.
This is how I tried:
[[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide];
[self.navigationController setNavigationBarHidden:hide animated:animated];
However, the duration of both animation is not the same. The status bar animation takes longer.
I found no way how to specify the duration of either animation.
Did I miss something obvious?
ios-lizard's answer is almost what I wanted but the navigation bar re-appears when rotating the device unless hidden is set correctly. So this worked for me:
Hidding animating works/looks nice YEAH!!.
Showing animation is OK, (I wish I could make the status bar slide with the navigation bar but at least we don't see gaps anymore. :D )
- (void)toggleFullscreen {
UINavigationBar *navBar = self.navigationController.navigationBar;
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
float animationDuration;
if(statusBarFrame.size.height > 20) { // in-call
animationDuration = 0.5;
} else { // normal status bar
animationDuration = 0.6;
}
_fullscreen = !_fullscreen;
if (_fullscreen) {
// Change to fullscreen mode
// Hide status bar and navigation bar
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:animationDuration animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x,
-navBar.frame.size.height,
navBar.frame.size.width,
navBar.frame.size.height);
} completion:^(BOOL finished) {
[self.navigationController setNavigationBarHidden:YES animated:NO];
}];
} else {
// Change to regular mode
// Show status bar and navigation bar
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:animationDuration animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x,
statusBarFrame.size.height,
navBar.frame.size.width,
navBar.frame.size.height);
} completion:^(BOOL finished) {
[self.navigationController setNavigationBarHidden:NO animated:NO];
}];
}
}
This is how I fixed this problem for my app.
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
// delta is the amount by which the nav bar will be moved
delta = statusBarFrame.size.height + self.navigationController.navigationBar.frame.size.height;
if(statusBarFrame.size.height>20) { // in-call
animationDuration = 0.5;
}
else { // normal status bar
animationDuration = 0.6;
}
// hide status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
// hide nav bar
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
self.navigationController.navigationBar.frame = CGRectOffset(self.navigationController.navigationBar.frame, 0.0, -delta);
[UIView commitAnimations];
Clearly, there's no easy solution to do this right. Apple has to fix it.
Of course, one work-around is to use alpha fading as Ephraim suggests. If you're insisting on the sliding behavior, I found it best to just animate the navigation bar and hide/show the statusBar without any animation. This looks much better than sliding the status bar because the gap between the bars during the animation is quite noticeable.
Here's a more concise method that uses system constants for animation duration and also handles incoming calls.
Note that navigationBar is an outlet and statusBarHeight is an instance-variable float.
- (IBAction)toggleControls:(id)sender {
BOOL isHidden = ! [UIApplication sharedApplication].statusBarHidden;
if (isHidden)
statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
[UIView animateWithDuration:[UIApplication sharedApplication].statusBarOrientationAnimationDuration animations:^{
self.navigationBar.frame = CGRectMake(self.navigationBar.frame.origin.x,
isHidden ? -self.navigationBar.frame.size.height : statusBarHeight,
self.navigationBar.frame.size.width,
self.navigationBar.frame.size.height);
}];
[[UIApplication sharedApplication] setStatusBarHidden:isHidden withAnimation:UIStatusBarAnimationSlide];
}
nacho4d's answer is almost what I wanted .but,He changes navBar's frame before navBar is visible. So we can't see transition animation.It looks like navBar appear suddenly. What is more, when showing, statusBarFrame.size.height is equal to 0. Here is his code:
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:animationDuration animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x,
statusBarFrame.size.height,
navBar.frame.size.width,
navBar.frame.size.height);
} completion:^(BOOL finished) {
[self.navigationController setNavigationBarHidden:NO animated:NO];
}];
when Showing , we wish we could make the status bar slide with the navigation bar. here is my answer:
UINavigationBar *navBar = self.navigationController.navigationBar;
[[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
// make navigationBar visual
if (!hidden)
{
[self.navigationController setNavigationBarHidden:hidden animated:NO];
}
navBar.frame = CGRectMake(navBar.frame.origin.x,
hidden ? -navBar.frame.size.height : 20,
navBar.frame.size.width,
navBar.frame.size.height);
} completion:^(BOOL finished) {
if (hidden)
{
[self.navigationController setNavigationBarHidden:hidden animated:NO];
}
}];
when hidding ,and hidden equal to NO. we should change navBar's frame first,then make navBar hidden.
when showing , and hidden equal to YES. we make navBar visual first,then change frame.
we choose UIViewAnimationOptionCurveEaseOut, to make it looks better.
You can use a instance variable to do this:
self.navigationController setNavigationBarHidden:hide animated:animated];
_shouldHideStatusBar = hide;
And implement the following function:
- (BOOL)prefersStatusBarHidden{
return _shouldHideStatusBar;
}
The setNavigationBarHidden:animated function will automatically call prefersStatusBarHidden function. If it doesn't you can call it with the following UIViewController's method:
[self setNeedsStatusBarAppearanceUpdate];
And of course you can choose your status bar hiding animation style with:
- (UIStatusBarAnimation) preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationSlide;
}
This isn't much of an answer but it works. So what I did is:
// This method gets called by whatever action you want
- (void) toggleShowStatusNavBars:(id)sender {
// Assuming you have a ivar called barsHidden
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4]; // This is IMPORTANT, 0.4s
self.navigationController.navigationBar.alpha = (barsHidden?1.0:0.0);
barsHidden = !barsHidden;
[UIView setAnimationDelegate:self];
[UIView setAnimationWillStartSelector:#selector(setStatusBarHidden)];
[UIView commitAnimations];
}
- (void) setStatusBarHidden {
[[UIApplication sharedApplication] setStatusBarHidden:barsHidden animated:YES];
}
This will basically synchronize the start of the animation (since you are calling setStatusBarHidden at the start of the navigation bar animation. The key part is that the status bar animation seems to take 0.4 seconds.
This works for me but if you find a better way, do post here.