iOS 7 UINavigationController Push animation shadow - ios

With iOS 7 a new push animation was created, which slides the pushed view controller on top of the hierarchy. But when the animation happens, iOS apparently does two things to modify the design of the top view controller:
A shadow is added:
And a light overlay over the bottom view controller:
In most applications this is not a problem. But, I am currently working on an application with pixel perfect design and I use view controllers with clear background. But this functionality remains the same, and the light overlay appears over the view controller. Because the background is a white gradient, this light overlay (on screenshot 2) is very visible and when the animation completes, it is removed without animation, which makes it very noticeable and annoying.
I am aware I can create custom animations and transitions, but I am wondering:
Is there any way to remove (or modify) this light overlay and shadow, without having to create custom transitions?
Thank you for your help.

It's not the most elegant solution, but I've seen people use UIImage animations to show what they want shown. So, you could:
Screenshot the incoming UIViewController
Animate the arrival of a UIImageView
Call pushViewController:animated:, passing NO for animated:
Remove the UIImageView
Again, a bit of a hack, but maybe it's the best solution for your scenario.

Try this proxy
[[UIImageView appearanceWhenContainedIn:NSClassFromString(#"_UIParallaxDimmingView"), nil] setAlpha:0.0f];
I don't know if Apple allows this or not because it uses a private API. Will update when app submitted.

Related

How to get UIVisualEffectView to blur without going OVER full screen / current context?

I have a SpriteKit game where I want to blur only a part of the screen (the board where the game is played). But at the same time, I want to be able to interact with the other elements (like UIButtons) on the screen. So basically I'm looking for something like a form sheet, but one that blurs what is under it and allows interaction with the main view controller.
So here's my problem. I've tried to:
put the UIVisualEffectView on my main view controller,
present another view controller modally with one of the standard presentation styles and have the UIVisualEffectView in there, or
present another view controller modally OVER full screen / current context and have the UIVisualEffectView in there.
None of these options work for me.
Options 1 and 2 don't actually blur. They produce a solid black box instead. (Although for some reason it blurs when I get a notification or when I pull down Notification Center or pull up Control Center. So I'm facing the same problem as this user.)
Option 3 does blur, but does not allow for interaction with the main view controller.
Does anyone know what else I could try? Or am I not using something correctly?
Unfortunately UIVisualEffectView simply doesn't work well with SpriteKit, even when using SKView. I've tried everything from A to zPositions.
I decided to recreate my UIButtons in the new view controller and present it modally OFS. That way I have access to the beautiful UIVisualEffectView blurring (SKEffectNode blurring isn't pretty at all IMO) and to my buttons. I hope Apple will work on the synergy of their frameworks in future versions of iOS and Swift. Then again, I'm not exactly an expert when it comes to app development, so if there is anything else I could've done I'd love to hear it :-)

How to recreate FaceTime's navigation view controller transition animation with overlapping transparent view controllers?

Short version:
I want to reproduce FaceTime's navigation transition animation to push transparent view controllers onto the navigation stack without the top view's content overlapping the bottom view's content.
Problem:
In a standard UINavigationController, pushing a destination view controller that has a transparent background results in an unsightly animation: the source view controller dims and translates, then pops out of existence. This is because the standard navigation push animation assumes the destination view controller has completely obscured the source view controller by the end of the animation, an assumption that is violated when the destination view controller's background is transparent. Please see this animation:
I have uploaded a demo project that re-produces this behavior at https://github.com/bgfriend0/PushVCWithClearBackground.
Desired effect:
Apple's FaceTime app, however, seems to be able to push a view controller with a clear background while simultaneously masking out the source view controller's content, so that the push animation is clean. Please see this animation:
I want to reproduce this FaceTime behavior, but I haven't found a solution.
Research:
Literature on the issue is surprisingly thin. I can find a few questions that touch on it (e.g., Segue Push Animation with Clear Background is Flashing on iOS 7 and Views getting darker when are pushed on navigation controller), but no solution actually resolves the problem by reproducing the desired FaceTime effect.
I found a link in a tweet (https://twitter.com/b3ll/status/384114227884986368) to the Apple dev forums on this issue, but again, no solution was forthcoming: https://devforums.apple.com/message/897379#897379.
Ideas:
The only workable solutions I've come up with are basically the same as those put forth by Caleb Davenport in the Apple forum post:
It's got to be one of three things:
(1) They are masking the left view up to the frame of the right view.
(2) They are copying the background contents into the right view while offsetting it such that the right view isn't really transparent.
(3) They are running custom view transitions.
Each of these has some degree of merit, but they're all quite complicated and I can't help but hope there should be, say, some convenient little flag Apple is taking advantage of to produce the desired mask effect. Of course, even if such a flag exists, it may be private API... nevertheless, I'm posting this question to see if anyone out there has come up with or can come up with an elegant solution to reproduce the desired FaceTime transparent push animation.
For anyone who may be interested, I did find an answer to this question in that Apple uses a private flag clipUnderlapWhileTransitioning on the UINavigationController and _UINavigationParallaxTransition classes.
See, e.g.,:
https://github.com/JaviSoto/iOS8-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UINavigationController.h
https://github.com/JaviSoto/iOS8-Runtime-Headers/blob/master/Frameworks/UIKit.framework/_UINavigationParallaxTransition.h
With this flag, I was able to completely reproduce the Facetime effect.
Naturally, all the usual caveats about using private API apply to this case (i.e., this is NOT allowed for Apps you intend to submit to the App Store).

iOS7 UITableViewCell background transparancy becomes opaque after a short pause

I have a UITableView which is presented modally over a view. One of the cells in the table view is deliberately transparent so that the view underneath is visable. The issue is that is IOS 7.1 the cell starts off transparent and then immediately becomes opaque. Under iOS 8 the transparent cell technique works perfectly.
Qn. Has anyone seen this and come up with a valid work-around?
Things I've tried
Adjusting cell.backgroundColor
Adjusting cell.backgroundView
Adjusting tableView.backgroundColor
Adjusting tableView.backgroundView
Setting tableView.opaque = YES;
Making the adjustments in tableView:cellForRowAtIndexPath:
Making the adjustments in tableView:willDisplayCell:forRowAtIndexPath:
Using full transparencies
Using partial transparencies
Using transparent images
[[UITableViewCell appearance] setBackgroundColor:[UIColor clearColor]];
Essentially as soon as any transparency is introduced into the background it changes (after a slight pause to become opaque).
To re-iterate under iOS7 the transparency is there very briefly (less than a 1/2 sec) then it turns opaque.
Here is a vimeo of the effect: Link
Rather than focusing on the tableview and it's cells, look at the presenting (bottom) view controller. I believe (although I can't find it officially documented at the moment) that when you do a standard modal presentation of one view controller over another, the presenting view controller's view is removed from the view hierarchy after presentation. Working with a trivial test app, the presenting view controller's -viewWillDisappear: is called and logging the key window's -recursiveDescription show the presenting view controller's view has been removed.
However, if you use a custom transition, the presenting view controller's view is kept in place (presumably to allow for exactly this kind of transparency effect).
EDIT: I've put together a quick example app (here: https://github.com/sjc/ViewControllerTransitionExample) to 1) illustrate the difference in behaviour between standard and custom modal presentation, and 2) to show how a basic UINavigationController subclass can be built to solve this issue (the technique is normally just applied to straight UIViewController subclasses).
However... While this can be used to solve the issue in this case, it doesn't answer the 'what's going on here?' question, since the example doesn't reproduce exactly what you are seeing: the presenting view controller disappears on both iOS 7 and 8, and not just on 7, as described in the original question. Oh well.
try to change to table cell from the Appearance system in your AppDelegate
[[UITableViewCell appearance] setBackgroundColor:[UIColor clearColor]];
This won't work on iOS 7 because modal views are always opaque. On iOS 8 they can be transparent.
You will have to find another solution on iOS 7.
That is seems to work for 1/2 of a second is because modal views aren't opaque during transition.

What's the proper way to implement complex custom view controllers

Note: I'm not talking about custom view controller transition effects which can be done by using a custom view controllers it's the iOS 5+ API.
I'm talking about transitioning to another view controller, where a view from the presently displayed view controller is animated to the view controller to be presented's view.
EXAMPLE
-you have friendsViewController which displays a list of the current users friends. Each table view cell has a profile picture and name.
-click on a cell, all other cells fade away and the name and picture animate to the top. At this point, UserProfileViewComtroller is displayed.
THEORIES
-I could easily do this by combining the two view controllers, but UserProfileViewComtroller can be launched from other parts of the app.
-if the UserProfileViewControllers view is instantiated, I could convert the coordinates using UIViews methods
I feel like there is a more appropriate/cleaner solution here which is why I'm asking the community for help :)
It seems to me that what you want is exactly about view controllers transition, since you want to do 'something' that would look to the user as if you took a view from old VC and moved it to the new VC.
Then you're in luck, as you're allowed to move a UIView from one view controller to another using [superview addSubview:view] as part of the transition you want to do.
This can be done on any iOS version, although it's easier now as in iOS 7 there's a delegate you write (see <UIViewControllerAnimatedTransitioning> reference) which has access to both VC's view hierarchies and can change them at will (move one view, fade other views) during transition period.
Also, making your new view controller during the transition transparent (or using old controller's snapshot) will help you hide the fact that VC changed.
Not so much an answer but a technique that might inspire a solution. I did an app that had need for a custom transition like this. The original app arranged itself then took a snapshot, so at the last moment the user is looking at an image. The second viewController was created, given coordinates etc, and the image, then shown immediately. It put the image into its view (subview with same bounds).
At this point the second vc has complete control, and can fade in some other content etc. the reverse was more or less as the start - the image is used, swapped, used removed to uncover the real view content.
Note that this took a bit of time to get it working with no glitches etc.
EDIT: if you are concerned in turning the whole original view into an image, then modify the technique. For instance, in the original view, fade all other content to black but the cell, then snapshot the one cell. The second view will start with an all black background, and place the cell image over top it, then go from there.
EDIT2: As mentioned in the comments, you of course push the second view with no animation, so it happens instantaneously. By setting a small image on the second vc, with an agreed upon background, you can quickly "pass the baton" so to speak and let the second controller go to work quickly and seamlessly.

UINavigationController with custom vertical button bar

I need to implement a navigation based app with a custom made button bar that stays on the vertical size of the screen, similar to Reeder iPad app (see Reeder screenshot).
What is the best way to achieve that result? I thought about adding the bar as a subview of the UINavigationController and calling its methods (like pushViewController:animated:) via the parentViewController reference from my button bar view controller, but it seems a bit convoluted.
Might work, but dangerous: set a transform on the CALayer object of the UINavigationBar. A transform that rotates the bar by "-1 * M_PI_2" would be almost right, you might need to translate it a few pixels too, to get the position correct.
Definitely works, but more effort: render a custom navbar, implement the delegate protocol from UINavigationController, and listen to the nav changing, and implement your own animations inside the callbacks.
(I've done the latter method to provide custom UINavigationBars - it works fine)
The only caveat with latter method is that your animations might pause / delay because by default they wait for each other to finish. If you look at the UIView animations, there's a setting that says "play immediately, even if other animations are in progress", and you might need to set that to YES.

Resources