I'm using UIViewControllerBasedStatusBarAppearance and preferredStatusBarStyle to manage the status bar color and appearance.
My app lets the user choose a photo from his camera roll and crop it to square using the native crop option of UIImagePickerController.
So I push a UIImagePickerController and enable editing to get the crop screen.
The problem is, I want that for the albums and photos view, the status bar will be white, and for the crop view I want to hide the status bar.
how can I do that with preferredStatusBarStyle ?
until now I made a category for UIImagePickerController and implemented:
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
this indeed set the status bar to white color in photos, but when going to crop view, the status bar becomes black, that could be good for me because I want to hide it and the background is black so you can't see it, BUT the battery indicator is green! so you only see the battery indicator in the status bar!
how can I solve that? how can I hide the status bar only in the crop view?
You will have to do a little bit of detective work here, but I can give you a lead.
I would suggest to subclass UIImagePickerController and return your statusbar preferences according to displayed child controller.
UIViewController has two methods that allow you to control statusbar visibility and appearance:
- (BOOL)prefersStatusBarHidden;
- (UIStatusBarStyle)preferredStatusBarStyle
Simply override them, no super call needed.
You have access to view controllers stack within subclass so you can choose preferred style and visibility for statusbar according to number of controllers on stack.
I have a feeling that UIKit will ping preferredStatusBarStyle and prefersStatusBarHidden each time new child controller pushed on stack.
If not then you can force UIKit to update statusbar by calling:
[self setNeedsStatusBarAppearanceUpdate]
Since UIImagePickerController is a subclass of UINavigationController you can assign your own delegate to it, monitor when new controller pushed on stack and call the suggested code above.
Sort of a followup to Andy's post, yes subclassing UIImagePickerController used to be forbidden but is allowed now. There's some unexpected issues trying to override prefersStatusBarHidden and preferredStatusBarStyle though.
Note how UIImagePickerController is a subclass of UINavigationController and so itself is a container for child view controllers. How a container view controller controls status bar visibility and style to its children is by overriding childViewControllerForStatusBarHidden and childViewControllerForStatusBarStyle. In general UINavigationController doesn't implement those and usually one overrides them to return the currently visible view controller.
In a case like this though, where you don't control the child view controllers, your picker subclass can override these methods to return nil, and then your implementations of the prefer methods should take over. In theory, you then just have to make them return what you need at the right time, but as evidenced by my experience, there's something fishy going on with UIImagePickerController and the status bar style.
For my own UIImagePickerController subclass, I don't care about child view controllers given its custom UI, but I've experimented with returning nil from childViewController.. and overriding the prefer methods. I've found that controlling the visibility to work fine, but something in the picker to counteract my subclass returning LightContent from preferredStatusBarStyle. See my own question.
Related
I use UISearchViewController to control my app's search stuff. I saw there's a property called hidesNavigationBarDuringPresentation for handling the navigationBar's visibility, but what I wanna do is to hide tabbar during presentation, I can't find any properties to do this.
Any work-around?
You're right that there's no property for explicitly showing & hiding the tab bar, but it's easy enough to implement yourself:
Make your view controller (not the UISearchController) implement UISearchControllerDelegate.
Assign your view controller to the search controller's delegate property.
Implement willPresentSearchController() (or didPresentSearchController()) and presentSearchController() to hide your tab bar. (The former is called when the search bar is automatically shown; the latter is called when you show it manually.)
Implement willDismissSearchController() (or didDismissSearchController) to show it again.
Note that if your implementations simply toggle the search bar's hidden property, then the bar won't animate in and out; you'll have to do your own animation.
It may be a good idea for your implementations to check the value of hidesNavigationBarDuringPresentation so that your tab bar is shown and hidden only when the navigation bar is.
I'm subclassing UIImagePickerController in attempt to override its default status bar behavior and having mixed results. My app uses view controller-based status bar appearance.
Without subclassing, I'm finding that it changes the status bar style to Default (dark) when the picker is dismissed, and nothing I've tried yet in my initial view controller is fixing it. Also, when the picker hides the status bar while being presented, sliding it upwards, the initial view controller's navigation bar slides up with it from height 64 to 44.
So I want my UIImagePickerController subclass to keep the status bar style as LightContent and, in an attempt to work-around the sliding navigation bar, keep the status bar showing while presenting the picker, then hide it on viewDidAppear:.
The first interesting thing is that preferredStatusBarStyle and prefersStatusBarHidden in my picker subclass weren't called at all until I also overrode childViewControllerForStatusBarStyle and childViewControllerForStatusBarHidden to return nil. This seems to indicate that normally, a UIImagePickerController is overriding those, probably to return an internal child view controller. Looking at the view hierarchy in viewDidAppear:, there's certainly a child PLImagePickerCameraView and its likely there's a controller to go with it. Sadly we cannot override this controller.
Overriding those childViewControllerFor... methods, preferredStatusBarStyle and prefersStatusBarHidden do get called in-between viewWillAppear: and viewDidAppear:, and can indeed keep the status bar visible and LightContent. The second interesting thing though, is that before the presentViewController animation the status bar briefly blinks dark. No amount of extra calls to setNeedsStatusBarAppearanceUpdate in viewWillAppear: or other places such as viewDidLoad: seem to prevent that.
The third interesting thing is that the bar style is still getting set to dark during dismissal, and no extra calls to setNeedsStatusBarAppearanceUpdate in the picker's viewWillDisappear: or viewDidDisappear: seem to prevent that.
tl;dr -- I've found that overriding UIImagePickerController to hide & show the status bar on demand to work pretty well, but setting the bar style is problematic. Something in the picker class or UINavigationController itself is automatically preferring the Default bar style, and when its switched to that on dismissal, it seems difficult to switch it back.
I've seen the Question UIImagePickerController breaks status bar appearance, and nothing I've seen there has helped yet, and iOS8.1 doesn't fix it. I was sure that setting the picker's navigationBar.barStyle to black would do it, but no dice. Any ideas anybody?
(Also, any tips on preventing a UINavigationController's navigation bar from sliding up to 44 height when the status bar is hidden would be useful thx)
Since apple introduced UIViewControllerBasedStatusBarAppearance and preferredStatusBarStyle in iOS 7 I'm trying to understand whats best practice to change status bar color for built in view controller, like:
UIImagePickerController
MFMailComposeViewController
UISearchDisplayController
for example, when using UISearchDisplayController, I want to change the status bar from light to dark when the search bar appears.
how can I do that? do I need to subclass UISearchDisplayController? maybe category?
and what about UIImagePickerController it has its own stack of view controllers, how can change the status bar style for all of them when presenting the photo picker?
until now I used the global why of
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
but now its all per-ViewController approach, so how would I modify controllers that are not mine?
Yes, you can subclass those classes to change the status bar appearance. According to UIImagePickerController, it's just a subclass of the UINavigationController, so, if you subclass and implement preferredStatusBarStyle in your subclass, all other view those appear on navigation will have the same status bar. Good Luck!
I am using a custom subclass of UINavigationBar with my UINavigationController by using: initWithNavigationBarClass:toolbarClass:.
Needless to say, in this subclass I need to monitor and update an additional interface element contained within my navigation bar subclass when the title of the presented navigation item changes. I have considered using KVO for this and observing the navigation items title property and updating as a when that changes but I was wondering if perhaps there was a better way. Would subclassing UINavigationController perhaps give me some more leeway to take control or monitor this function? I am interested to hear your thoughts on this one and whether or not there is a better way to go about this?
To elaborate: I am overiding some methods for example layoutSubviews. In this method when the navigation item has just been pushed onto the stack it doesn't yet have a title. This is because the title is set in the view controllers viewDidLoad which won't be executed until the view is loaded which has not happened yet. As such even though the navigation item has been pushed the title is still nil until it is changed in the presented view controllers viewDidLoad. This is what I want to be notified of when the navigation item is changed after it has been pushed onto the navigation stack.
I have a navigation controller with a custom background navigation bar. I am using iOS 5's UINavigationBar "appearance" attribute to set the background image.
I am doing so in the applicationDidFinishLaunchingWithOptions app delegate method in order to change the background image across all nav bars. Trouble is, I need to change the navigation bar color to UIBarStyleBlackTranslucent for one single view controller.
How can I do this without having to go back and change every single view controller?
Subclass the UINavigationController and have the popViewControllerAnimated method of your subclass reset the background image/color then call super's popViewControllerAnimated.
This assumes you are using a UINavigationController, which I think you are.