Cross-fade certain UIViews on device orientation change - ios

I've got a bit of a query on how certain views rotate when an iOS device changes orientation.
I'm developing an app right now, and it basically consists of 2 view controllers: the first being a UITableViewController embedded in a UINavigationController, the second being a completely custom one being built on a stock standard UIViewController.
I've noticed that on my UINavigationController view, when the device rotates, the UINavigationBar and the UIToolbar both perform a cross-fade animation when transitioning to their landscape dimensions.
For technical reasons, I didn't use a UINavigationController for my custom view controller, but I manually added a UINavigationBar and a UIToolbar in the same places to it (Basically because I need those elements to be able to be overlaid on top of the background view, as they can optionally be hidden and I wanted direct control to do that).
However, when I rotate my device when my custom view controller is visible, the two bars do NOT perform a cross-fade transition. Instead, all of the subviews slide around (looking a bit chaotic), and the background image distorts as it immediately gets swapped over to the iPhone landscape version before the animation actually starts (ie, so it starts off tiling the 32pt high artwork inside a 44pt high UIToolbar).
I was just wondering, does anyone now how Apple actually goes about creating this cross-fade blending effect for certain UIViews when the device orientation changes?

Don't use native auto-rotation rotate your view. Rotate them manually. Look the second answer here:http://stackoverflow.com/questions/1220580/iphone-dev-manually-rotate-view . Essentially you sign up for device rotation notification and do the view rotations yourself.
If you want to crossfade the two views in addition to the UIView animate block specified in the link above go:
[UIView transitionWithView:superViewOfButtonView duration:2.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[thebuttonViewIWantToCrossFade setFrame:newPositionRect];
}completion:^(BOOL finished){
//any completion code
}];
Let me know if this works for you!

I actually came back and re-explored this. While the UIView and CAAnimation transition methods do indeed work, their respective framerates on different iOS devices vary so wildly that I didn't think implementing them was the best solution.
I finally bit the bullet and contacted Apple Developer Relations and asked them directly (If you didn't know, each Mac/iOS developer may ask 2 questions to these guys for free each year!).
They replied promptly, and informed me that several Apple engineers actually presented a talk on that exact topic at WWDC 2012.
The talk was recorded, and is available to registered Apple developers on iTunes under the title "Polishing Your Interface Rotations". It covers many different methods on handling interface orientation and is really worth watching. :)
Hope this also helps!

Related

How to show double height green statusbar (In-Call) in foreground app on device?

There's a lot of questions here asking for displaying a red recording bar while in background. It's totally clear I should use AVAudioSession category AVAudioSessionCategoryPlayAndRecord for that. My question is how can I display a green In-Call bar (or at least red bar) in a foreground app when having an active VOIP call in my app? So I could return to call UI tapping a statusbar area, just like Whatsapp or Skype does.
What I've already tried:
voip and audio modes in UIBackgroundModes key in Info.plist + setCategory:AVAudioSessionCategoryPlayAndRecord + setActive as suggested in this SO answer (gives me a red statusbar when going background, but nothing while in foreground)
Previous + AVAudioSession + setMode:AVAudioSessionModeVoiceChat - didn't work
Set kCFStreamNetworkServiceTypeVoIP flag to socket in pjsip sources and recompiled it - didn't help. Also, deprecated since iOS 8.
Created a separate socket, set the voip flag for inputStream/outputStream: [self.inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] (took the sample code from here)
Using pjsip for calls. What else can I try to increase a statusbar height, moving all the UI down?
Are there any standard ways to do that, or I should hack it my own by resizing a root UIWindow and setting another green UIWindow under the statusbar?
Edit:
Since no answer is found for a standard way to do that, accepted #roman-ermolov answer. For those who will search for an answer I may suggest several options to do it yourself:
Wrap your root viewcontroller inside container, like in Apple's iAdSuite with Storyboards example. Take a look at my sample project for example. Probably the best way to make that bar.
Hack UINavigationBar height (see this approach) - doesn't work for landscape yet, but may probably be solved
Control your main UIWindow's frame yourself, place another UIWindow under the statusbar with the desired content.
I have made an investigation of both apps (WhatsApp & Skype) and learned that they used their own UIView for achieving this functionality.
This is Skype:
This is WhatsApp (Reveal can't get real snapshot, but it transmits basic idea):
In both apps it is a UIView which starts on top of the screen and several methods for format output text / handle touch on it.
In iOS 10 Apple introduced CallKit.framework, but it seems that it has not that kind of functionality too, so the only way to do it - do it yourself.
Roman Ermolov's answer explained that some apps use their own UIView for this functionality, but does not explain how. The way I see it, you have a few options.
If you want to lay the view on top of (and covering) the current view controller, you could create a UIView with a UILabel or your own UIWindow and add that as a subview of your applications' keyWindow.
To have the view stick on top without covering the contents of the view controller, you could take the same approach as above and manually resize the application window or window's root view controller when you add the call bar subview. Alternatively, you could create a UIViewController base class which contains this call bar subview and an outlet for the view's height constraint. The default value of this constraint should be zero. Then, when a call is placed, change the height constraint to your desired call back height. This constraint approach might work on the application's UIWindow as well, but I'm not too familiar with using constraints on an application's window.

How to fade in/out navigationBar on iOS 9?

Built-in Photo application fades in/out navigationBar when you tap on an image . This way Photo app allows to see it full screen.
How does it do this (fade efect)?
As I understand navigationController?.navigationBar.alpha doesn't work anymore (so you can't animate it this way).
Sharing all my finding.
Complain mode on
Frankly, I feel half pissed/like a dummy that I had to fight a good day to implement simple thing existing in Apple app.
Complain mode off
First of all here is some context. I am working with navigationBar which are provided by navigationController (vs just standalone bars which are manually dropped in your view)
There are several approaches which I found. I will mention all of them (even if I had no success using them)
1) Animate change of alpha of navigationBar
UIView.animateWithDuration(0.1, animations: {
navigationController?.navigationBar.alpha = 0
}, completion: nil)
#rmaddy mention here that it works for him. However, I believe he has a standalone bar (vs a bar managed by navigationController).
I used a tool Reveal to check UI hierarchy and found couple of things.
- There is a navigationBar which is hidden (and navigationController?.navigationBar is referencing it). So you can change alpha to your hearts joy, but these changes won't be visible.
There is however another navigationBar . I assume it's referenced in some private members of navigationController (let's call it private navigationBar). It's visible and that's what is displayed at the top of your view.
2) Use setNavigationBarHidden:animated:
This is a standard way to hide/show navigation bar. It's animated different way (it slides/up and down). However, if it's ok for you, just go with this is, because it's simple and clean.
navigationController?.setNavigationBarHidden(true, animated: true)
Additionally you can wrap it in UIView.beginAnimations, UIView.commitAnimations to animate it together with some other stuff (to make it smoother)
3) Animate change of alpha of private navigation bar.
This worked for me:
let privateNavigationBar = self.superview?.superview?.superview?.superview?.superview?.superview?.subviews[1]
UIView.animateWithDuration(0.1, animations: {
privateNavigationBar.alpha = 0
}, completion: nil)
I am going way up through the hierarchy to get a view which contains private navigationBar (which is second subview for that view).
However, this approach has multiple downsides:
I believe # of superviews? depends on your app hierarchy (vs you are using split view and so on). I think you can generalize or may be you just walk the whole hierarchy to find non hidden UINavigationBar to solve this.
I have a feeling that Apple may frown at this (your app be not accepted to AppStore)
4) Make navigationBar transparent and set background image to be transparent and change alpha channel on it.
I can't find where I read about this idea. There was couple of mentioning.
There is Apple example app which shows how to customize NavigationBar, including making it transparent.
It's interesting that this example app works for me (the navigation bar is transparent in it). However, when I tried this code in my app it didn't work (I still didn't figured out what is going on with this). As usual there are bunch of variables (may be something in Info.plist, also they subclass NavigationController, also may be something in view hierarchy)
5) Adding standalone navigationBar
You can hide a bar provided by navigationController. Add your own to the UIView, wire it to #IBOutlet and use alpha animation on it (most likely that's what #rmaddy was referring too).
I checked and this is work.
This approach is used in this tutorial.
However, it has a downside:
I believe it won't handle well rotation, increase of statusbar height while call or GPS
Each time when I see a code like this (written in the article) I know that there will be problems with resizing: CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64.0)
You can potentially replace it with constrains. I went this route, but stumble upon some issues.
6) Other methods
I saw two more methods. I don't know whether they will work or what will be downsides:
One of them in this question: How to hide/show status bar and navigation bar by fading in/out at the same time like the Photos app in iOS 7?
And this answer: https://stackoverflow.com/a/18063898/422080

3dtouch to present(peek without pop) UIView like contacts app

I'm trying to implement 3D Touch feature that presents a summary of information (like Peek). But I don't want that it pops. I just want to preview the information like contacts app does with contatcs:
It only presents an UIView and doesn't deal with two levels of force (peek and pop).
How can I do something like this?
Ps.: I don't want to deal with long press gesture.
Introduction
Hello
I know this is a bit to late, probably, but in case someone else stumbles upon it: I certainly believe it is possible and I don't think its a "native behavior for contacts". Although it would not be as simple as the UIKit api for peek pop views. You would need to:
Steps
subclass UIGestureRecognizer (perhaps it may work with the UITapGestureRecognizer also), and register UITouches and use their force property.
Setup a UIViewController with transparent but blurred background around the edges (together with a modalPresentationStyle .overCurrentContext if i recall correctly), with your desired content in the middle (much like the peek view). Then add a UIPanGestureRecognizer to the center view for dismissal/sliding up the buttons.
And then create a custom animation transition for that UIViewController to be triggered once the force property of the registered UITouches from the subclassed UIGestureRecognizer is high enough. And then reversed once the force property gets low enough.
Concluding notes
I believe this is a bit of a tedious task and there might be a simpler way. For example, a simpler way using a 3rd party library for long pressure gestures (that registers size of the touch), but it would not give the same feel.

UIView switching animation for landscape and portrait scene in storyboard?

I'm trying to design different layouts for my view controller. After googling, I've got this answer from SO. Basically, the answer instructs me to setup 2 scenes, one for landscape and one for portrait, when the device rotates, hide one and show the other one.
And my question is what if I want to add a sweet animation for the rotation process? For example, since I can setup the same view on different scenes, can I set the motion path for these views and disappear? Or, if it is easier, can I add some rotation and fade out animation?
I'm quite green with Core Animation, so a detailed explanation is very useful for me. Big big thanks in advance!
There are a few options here. The main methods you are looking for to do any of this are:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration;
and
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
If you want to move the elements around the screen while the rotation is happening you will be best off changing the frames of the elements rather than creating a separate view file. Using any motion animation would require some mapping between the two and I have never heard of anything like this before. Again, if you just change the frames though, you can preform basically any screen movements you would like (for views and subviews).
To do the fading you could just throw an animation block in the first method:
[UIView animateWithDuration:duration
animations:^{
// set alphas for old and new views here.
}];

Changing iPad orientation, rotating statusbar, toolbars, but not the main view

I’m trying to set up an iPad test application, window-based, where I have a single view controller and a single view. When I rotate the iPad, I want the orientation of the toolbar to change, but not that of the view itself. For example, a sort of background view that you work in is fixed to the device, but the status bar and toolbars rotate around it. This would enable the user to work the view from all angles, but always with a correctly-oriented toolset.
A beautiful implementation of what I want can be found in the Brushes for iPad app, where the painting’s orientation is locked to the device, and the toolbars rotate around it. I think other painting apps do the same thing.
I’ve been trying to figure out how to do this, but after exhausting many many other questions here concerning orientation, I’m still at a loss.
Could anyone point me in the right direction towards a neat solution? A particular combination of autoresizes for the autoresizeMask? Countering the rotation animation with another one in the opposite direction? Using multiple concurrent view controllers, one for the rotating views and one for the non-rotating ones?
I’d very much appreciate it,
(Edit: Attempted to clarify the question, after Olie’s comment.)
To prevent rotation, you'd put this in your view controller's .m:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
But you say you still want the view frame to resize in response to the rotation. I haven't had a need to do this myself, so I'm not sure if it's sufficient to just set the autoresizingMask to have flexible width and height; you may also have to implement didRotateFromInterfaceOrientation: and use setNeedsLayout and/or resize the view manually.
I had a bug that did this a while back -- I'm pretty sure that what you're asking will get you a HIG-violation rejection from Apple. However, I'll give a shot at remembering what the problem was. I'm pretty sure it was something like this:
I had a tabbarViewController that said "I orient to any orientation."
One of the tabs was a regular-old UIViewController that said "I only do LandscapeLeft & L-Right"
When you rotated, the inside (UIVC) stayed put, but the outside (TabVC) rotated around things.
I might have some of the details backwards or otherwise convoluted, but the general ideas is: stacked VCs, not all one VC.
Good luck!
To the extent I have worked with I cannot see any simple answer to your question. What about rotating everything (tabbar, nav and status bar, your view controller) and then redrawing the content of your view controller in "old coordinates" so for the user it will look like it's not rotated?

Resources