How to make uiview fullscreen viewcontroller using custom transitions ios7 - ios

What i want to achieve is: after tapping a small view with some data i want to make it full screen and possibly make it to be a new vc.
For now I animate uiview to full screen with great success, but whole logic of this view is in it's "parent".
Is it possible to animate viewcontroller out of the uiview which is similar (for. eg. like in LayoutTransitions in Android SDK)?
Sample code of my uiview to full screen using autolayout:
sender.view.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:0.2
animations:^{
sender.view.frame = self.view.window.bounds;
} completion:^(BOOL finished) {
[((CSTicketView*)sender.view) showMenu];
}];
[[UIApplication sharedApplication]
setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationFade];
[[self navigationController] setNavigationBarHidden:YES animated:YES];

Let's move your sender view to Window as like below,
AppDelegate * appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:sender.view];
[UIView animateWithDuration:0.2
animations:^{
sender.view.frame = self.view.window.bounds;
} completion:^(BOOL finished) {
[((CSTicketView*)sender.view) showMenu];
}];

Absolutely possible.
You can use the new view controller transitions model in iOS7.
I would definitely recommend a few resources to check on top of my basic explanation:
this
and this
I have some sample code for a demonstrator of this here
Ultimately you make a new view controller for the view you are transitioning to, and you also make an NSObject subclass that conforms to UIViewControllerAnimatedTransitioning which contains the code to transition between them. Sounds complex but if you watch the video I linked to and read the other reference it'll make total sense.

Related

Setting rootViewController causes black screen blink before is loaded

I got strange behaviour when setting the rootViewController programatically. I am using xib's only and here are scenarios of what I already tried.
When I use this code, there is a small blink of black screen before it loads VC correctly.
- (void)setRootVC:(UIViewController *)viewController {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[UIView transitionWithView:window
duration:0.0
options:UIViewAnimationOptionTransitionNone
animations:^{ window.rootViewController = viewController; }];
}
When I use different function, it eliminates the blink, but there's another strange behaviour. I got bunch of textfields in the new VC and I am setting one of them to becomeFirstResponder in viewDidLoad method, but when the VC loads, the textFieldDidEndEditing is called, which is totally strange. Here's the code.
- (void)setRootVC:(UIViewController *)viewController {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[UIView transitionFromView:window.rootViewController.view
toView:viewController.view
duration:0.0
options:UIViewAnimationOptionTransitionNone
completion:^(BOOL finished){
window.rootViewController = viewController;
}];
}
I am restricted with objective-C, so swift solutions will not be helpful. Thanks for the replies.
The blink is caused due to you are setting the rootViewController in completion where is it should be in animation block, so the code below might be helpful for you..
[UIView transitionWithView:self.window
duration:0.5
options:UIViewAnimationOptionTransitionNone
animations:^{ self.window.rootViewController = viewController; }
completion:nil];
Instead of using UIViewAnimationOptionTransitionNone you might want to add some transition effect so, you can use UIViewAnimationOptionTransitionCrossDissolve instead, it might look better..
Hope it helps.
Cheers.

How could I present a viewController while still see the background viewController

The Photo Sharing part is a ViewController I wrote, when I press the right item, the PhotoSharingViewController will appear animatedly.
Here is my code:
PhotoSharingViewController *vc = [[PhotoSharingViewController alloc] init];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[UIView animateWithDuration:0.3 animations:^{
vc.view.frame = CGRectMake(0, 0, WIDTH, WIDTH * 0.8);
} completion:^(BOOL finished) {
}];
However, I do not think it is a good way. I prefer to "present" the viewController, like UIAlertController, or UIActivityViewController. How could I do that, please?
You want to provide a custom transition. That way, when presentViewController is called, you get to provide the UIPresentationController as well as the animation. You are in complete charge of both where the presented view goes and how it animates to get there.

Custom Segue Animation Flicker

I am building an application using UISplitViewController as my root view controller (as prescribed by Apple). However, I needed a custom view for login / management to be displayed prior to the UISplitViewController, so I created a custom UIStoryboardSegue that calls some custom animations. I am attempting to recreate the push / pop segues through a modal segue, without actually pushing an popping view controllers. I've implemented everything correctly, however, at the end of my animation I have a flicker. Here is a gif of it:
Here is my custom Segue's code:
- (void)perform {
UIViewController *srcViewController = (UIViewController *) self.sourceViewController;
UIViewController *destViewController = self.destinationViewController;
UIView *prevView = srcViewController.view;
UIView *destView = destViewController.view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:destView aboveSubview:prevView];
[destView enterRight:0.1 then:^{
[destView removeFromSuperview];
[srcViewController.presentingViewController dismissViewControllerAnimated: NO completion:nil];
}];
}
And here is my custom animation (Implemented as a category on UIView):
-(void)enterRight:(float)delay then:(void(^)(void))after
{
CGPoint moveTo = self.center;
CGPoint moveFrom = self.center;
// Grab a point from off the screen
CGFloat simpleOffscreen = [UIScreen mainScreen].bounds.size.width;
// come from off the right side (+)
moveFrom.x = moveFrom.x + simpleOffscreen;
self.center = moveFrom;
self.hidden = NO;
[UIView animateWithDuration:0.5
delay:delay
usingSpringWithDamping:1
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseIn
animations:^
{
self.center = moveTo;
}
completion:^(BOOL finished)
{
if (after) after();
}
];
}
As you can see in the Segue, I am animating the view into the current view controller, then without animation presenting the actual destination view controller. I think this is where the flicker is introduced, yet I am unsure about how to go about preventing this.
My Storyboard for this custom segue is
Anyone know how to implement this?

Present a transparent modal UIViewController

I'm trying to make a custom alertView (for iOS7+) on my own but I struggle with the alertView presentation.
I have a UIViewController with a black background (alpha set to 0.25f), and a alertView as subview.
When I want to show the alertView, I present modally the viewController:
-(void) show
{
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
self.modalTransitionStyle = UIModalPresentationCustom;
self.transitioningDelegate = self;
[window.rootViewController presentViewController:self animated:YES completion:nil];
}
And here is my animator object:
-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
NSLog(#"%s",__PRETTY_FUNCTION__);
return 2;
}
-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
NSLog(#"%s",__PRETTY_FUNCTION__);
UIView* toView = [transitionContext viewForKey:UITransitionContextToViewKey];
toView.alpha = 0;
UIView* container = [transitionContext containerView];
[container addSubview:toView];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toView.alpha = 0.5;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
The thing is: the modal VC is fading with the presenting VC in background as its supposed to do, but when the animation ends the presenting VC is removed from the background.
If I call [transitionContext completeTransition:YES]; instead, the presenting VC is in background but the modal VC is removed at animation end, so I guess the context cancels the presentation if we send 'NO'.
Is there a way to keep the presenting VC in background without having to make a snapshot of it and set it as background of the modal VC's view?
I've tried this solution and it works on both iOS 7 and 8:
if ([[UIDevice currentDevice].systemVersion integerValue] >= 8)
{
//For iOS 8
presentingViewController.providesPresentationContextTransitionStyle = YES;
presentingViewController.definesPresentationContext = YES;
presentedViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
}
else
{
//For iOS 7
presentingViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
}
Note: Be aware of the difference between 'presentingViewController' and 'presentedViewController'.
iOS8+
For iOS8+ you can use below code snippet
SecondViewController *secondViewController = [[SecondViewController alloc] init];
secondViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:secondViewController animated:YES completion:nil];
My case might differ from yours, but the information might be useful for the conversation.
In Storyboard, I changed my segue's Presentation to state "Over Full Screen" and it did the trick.
I think what you are seeing is the default behavior of iOS.
View controllers are not supposed to be non-opaque when presented as modal view controllers. iOS removes the underlaying view controller when the animation is complete, in order to speed up composition when the presented view controller is supposed to take up the entire screen. There is no reason to draw a view controller - which might be complex in it's view hierarchy - when it is not even visible on screen.
I think your only solution is to do a custom presentation.
Remark: I did not test this. But it goes something like this.
/* Create a window to hold the view controller. */
UIWindow *presenterWindow = [[UIWindow alloc] init];
/* Make the window transparent. */
presenterWindow.backgroundColor = [UIColor clearColor];
presenterWindow.opaque = NO;
/* Set the window rootViewController to the view controller you
want to display as a modal. */
presenterWindow.rootViewController = myModalViewController;
/* Setup animation */
CGRect windowEndFrame = [UIScreen mainScreen].bounds;
CGRect windowStartFrame = windowEndFrame;
/* Adjust the start frame to appear from the bottom of the screen. */
windowStartFrame.origin.y = windowEndFrame.size.height;
/* Set the window start frame. */
presenterWindow.frame = windowStartFrame;
/* Put the window on screen. */
[presenterWindow makeKeyAndVisible];
/* Perform the animation. */
[UIView animateWithDuration:0.5
delay:.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
presenterWindow.frame = windowEndFrame;
}
completion:^(BOOL finished){
/* Your transition end code */
}];
This does however leave you with no option to use any of the presenting view controller logic build into UIViewController. You'll need to figure yourself, when the presented view controller is done, and then reverse the animation and remove the UIWindow from screen.
The ViewController is not supposed to be transparent when you present it or push it. You can try adding it as subview. And for transition effect change its frame immediately after adding as subview. Make its frame somewhere outside the visible view and then animate it to change frame to visible view.
Hope this helps.
For your information,
I finally made my custom alertView a subclass of UIView for the "popUp part".
To show it, I just add the alertView as subview of the keyWindow with the constraints to center it, and put a transparent black background view behind it.
As it's not a controller, I have to manage UI rotation by myself (only for iOS 7, it rotates well with the UI in iOS 8).

Switch between two UIWindows

I am integrating Pushwoosh SDK for Push Notification, which is using UIWindow to represent HTML page sent from Pushwoosh portal
- (void) showWebView {
self.richPushWindow.alpha = 0.0f;
self.richPushWindow.windowLevel = UIWindowLevelStatusBar + 1.0f;
self.richPushWindow.hidden = NO;
self.richPushWindow.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.3 animations:^{
self.richPushWindow.transform = CGAffineTransformIdentity;
self.richPushWindow.alpha = 1.0f;
} completion:^(BOOL finished) {
}];
}
- (void) showPushPage:(NSString *)pageId {
NSString *url = [NSString stringWithFormat:kServiceHtmlContentFormatUrl, pageId];
HtmlWebViewController *vc = [[HtmlWebViewController alloc] initWithURLString:url];
vc.delegate = self;
vc.supportedOrientations = supportedOrientations;
self.richPushWindow.rootViewController = vc;
[vc view];
}
And on closing on HTML page it calls
self.richPushWindow.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.richPushWindow.transform = CGAffineTransformMakeScale(0.01, 0.01);
self.richPushWindow.alpha = 0.0f;
} completion:^(BOOL finished) {
AppDelegate * appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
self.richPushWindow.hidden = YES;
}];
Now I want to call my view controller on closing of this HTML page. So I tried to present myviewcotrlller in this block completion but not presenting.
Actually here problem is that there are two UIWindows in my app one of app and other used by sdk. Now if i try to present view controller from this html page which is on separate UIWindow so it creates a separate hierarchy and when i close this window also removes my presented viewconroller due to parent-child relationship. And if do not close this window then how to come back to actual flow of app.
I want that new controller should be presented from that new window and after that window should be close and flow of app should not be affected by additional window. Is it possible? If my concept is wrong, Please help if anyone has idea
Edit: second uiwindow never be key window, it only becomes visible by setting higher windowlevel and become hidden
The problem is that right after this completion block richPushWindow will be gone, effectively this means you are trying to present view controller on a hidden window.
The solution is very simple. Use main window to present view controller. Some pseudocode:
Add view from the ViewContoller to the main window subviews:
[appDelegate.window addSubview:myViewController.view];
Modal:
[appDelegate.window.rootViewController presentModalViewController:myViewController]
Using View Controller hierarchy:
Push your viewController to the main viewController stack. For example if you have navigationController, just push it there.
I hope it helps!

Resources