I'm working on a project that displays a PDF using QLPreviewController from two different views. One view pushes the QLPreviewController onto the base navigation, and the other one is a modal view that brings the QLPreviewController up in modal.
I had issues when I initially set this up with the push including setting the nav bar opacity and the nav bar blocking my PDF. I was able to solve both issues by subclassing the QLPreviewController:
#import "CustomPreviewController.h"
#interface CustomPreviewController ()
#end
#implementation CustomPreviewController
-(id) init {
self = [super init];
if(self){
// init
} return self;
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// set translucency of navigation bar
self.navigationController.navigationBar.translucent = NO;
// nav bar does not overlap content
self.edgesForExtendedLayout = UIRectEdgeNone;
self.automaticallyAdjustsScrollViewInsets = YES;
}
#end
However, now I need to view the same PDF from a different flow in the app. For this design I need a modal pop up to a UITableView, then either a push or a modal from that tableview to a PDF in the QLPreviewController. When I use the same push animation I get a delay and fracturing of the animation and a glitchy toolbar at the top. (See this post here). When I use a modal it animates smoothly but my UINavigationBar is hiding the top of the PDF and covering the page number. Similar nav bar symptoms to the push issues in the linked post. I have tried the solution proposed there, as well as attempting to hide the nav bar of the initial modal and the preview controller, to no avail.
This might be an Apple bug/issue but if anyone has discovered a usable workaround any suggestions would be welcome.
Related
I have a UIViewController on the More... tab. In viewDidLoad, I set toolbarHidden to NO, and the toolbar appears. However, if I select another tab from More..., then when I return to my original UIViewController, the toolbar is hidden (toolbarHidden is YES). I've checked to be sure it's the same view controller object.
My workaround is to set toolBarHidden to NO in viewWillAppear.
Is this documented behavior that I'm missing or is it a bug?
UPDATE
Here is some fairly trivial sample code. It turns on the toolbar in viewDidLoad and offers a button to toggle the toolbar on and off.
// Test_VC.m
#import "Test_VC.h"
#implementation Test_VC
- (void)viewDidLoad {
[super viewDidLoad];
// for testing to turn the toolbar on and off
UIBarButtonItem *sampleButton = [[UIBarButtonItem alloc]
initWithTitle:#"Toggle TB"
style:UIBarButtonItemStylePlain
target:self action:#selector(toggleToolbar:)];
self.navigationItem.rightBarButtonItem = sampleButton;
// the toolbar should re-appear whenver this view controller is selected
self.navigationController.toolbarHidden = NO;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// if on More..., this line will keep toolbar visible
//[self.navigationController setToolbarHidden:NO animated:NO];
}
- (void)toggleToolbar:(UIBarButtonItem *)sender
{
[self.navigationController setToolbarHidden:!self.navigationController.toolbarHidden animated:YES];
}
#end
To test:
Create a project with numerous tabs, each of which is an instance of this view controller, Test_VC. Have enough tabs so that at least two of these controllers are on the More tab.
Run the app.
Go to the More tab.
Select a "Test_VC" on More (I refer to this as "Test_1"). Notice that the toolbar appears.
Select another Test_VC from More. (I refer to this as "Test_2"). Notice that the toolbar also appears.
Touch "Toggle TB". Notice that the toolbar goes away on Test_2.
Touch More.
Reselect the first Test VC ("Test_1"). Notice that the toolbar is no longer there.
Repeat these tests using Main tab view controllers. Notice that there is no interactions with any others.
In step 4, the toolbar for Test_1 was present. In step 6, the Test_2 toolbar is removed. However, in step 8, the Test_1 toolbar is gone, too, but no change was made to the Test_1 VC.
This demo turns the toolbar on and off via the Toggle TB button. In my app, some of my view controllers simply hide the toolbar in viewDidLoad and some don't. This demo code could be modified to make two view controller versions: some that show the toolbar in viewDidLoad and some that hide the toolbar in viewDidLoad (no need for the Toggle button).
If these view controllers are main tabs (step 9), then each operates independently of the others, as expected.
What I have found: Toolbar visibility on all view controllers launched from More is set by the most recent More view controller that executes viewDidLoad. Thus, viewDidLoad is strange for More tab view controllers.
It's as if there's only one toolbar managed by More. I do not understand this behavior.
I'm building an iOS app using a NavigationController. However, in this app I need a sub navigation bar and it needs to be in every view. I initially implemented this using a toolbar in every view. But what happens, when a new view slides in, is that the toolbar slides in as well. I need the toolbar to be persistent, like the navigation bar. What's the best way to approach this?
My best guess is to set [self.navigationController setToolbarHidden:YES animated:YES]; to YES and then somehow positioning that underneath the navbar...
This is how I used to do it in every viewcontroller:
#interface TableViewController ()
#property (weak, nonatomic) IBOutlet UIToolbar *mainToolBar;
#end
#implementation TableViewController
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setToolbarHidden:YES animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"TV Shows";
[self addRightMenuButton];
[self loadNinjas];
self.mainToolBar.barTintColor = [UIColor whiteColor];
self.mainToolBar.layer.shadowColor = [[UIColor blackColor] CGColor];
self.mainToolBar.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
self.mainToolBar.layer.shadowRadius = 3.0f;
self.mainToolBar.layer.shadowOpacity = 1.0f;
self.tableView.dataSource=self;
self.tableView.delegate=self;
}
Three distinct approaches I can think of trying:
Make a taller Navigation Bar subclass with your secondary toolbar thing at the bottom. Set it as the Navigation Controller's Navigation Bar. I've tried this a couple of times to achieve different things and it didn't work out, but maybe it will for you.
Stick with what you're doing, a second toolbar on every VC, and use a custom VC transition or presentation controller to make it appear like the toolbar isn't moving while the rest of the content is.
Don't do this. I can't really see a way that a double navigation thing is going to be good for an iPhone app.
When my app returns from background, the UIViewController jumps down the height of the UINavigationBar (44 pixels).
Everything is being controlled through a story board using push segues.
Even when I NSLog the frame of both the view controller and the navigation controller after the "jump", using NSStringFromCGRect, they both show (0,0,320,480) as their frame, even though its clearly not the case.
Before:
After returning from background:
You can use this code for hide navigation bar in YourViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self.navigationController.navigationBar setHidden:YES];
}
I've tried my app on iOS 7.1 and I found that the tab bar background disappears on a few occasions. I was able to track them down; it happens when:
pushing a view controller placed inside navigation controller (that is inside tab bar controller) with hidesBottomBarWhenPushed = YES
presenting a view controller and then dismissing it (i.e. the MFMailComposeViewController)
I've created a sample app (used the tab bar template + added button to display the view controller, and a mapView to be able to tell if the bar disappeared), and the issue is there.
Here is all the code for the sample app that I changed:
#import "FirstViewController.h"
#import MessageUI;
#interface FirstViewController () <MFMailComposeViewControllerDelegate>
#end
#implementation FirstViewController
- (IBAction)presentVCButtonPressed:(id)sender {
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"Feedback for Routie"];
[mailer setToRecipients:#[#"support#routieapp.com"]];
[self presentViewController:mailer animated:YES completion:nil];
}
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Here you can download the whole sample project.
Now, important thing: this seems not to affect iPhone 5, nor the simulator. The problem is on iPhone 4 and iPod Touch (last generation as of writing this post).
Does any of you have the same problem? Were you able to fix it?
Thanks!
Update: I found a workaround. See my answer below.
Fix found!
So after some investigating (and headache), I found out that there is a simple fix. Just toggle the translucent property, like this:
tabBar.translucent = NO;
tabBar.translucent = YES;
Now as for when to do this, there are several places for each case:
1) pushing viewController with hidesBottomBarWhenPushed = YESThe bar background disappears right after the pop animation finishes, so add the fix to the viewDidAppear: method of the viewController that presented it:
- (void)viewDidAppear:(BOOL)animated {
self.navigationController.tabBarController.tabBar.translucent = NO;
self.navigationController.tabBarController.tabBar.translucent = YES;
...
}
2) Presenting a view controller and then dismissing it:In this case, the tab bar background is already gone during the dismiss animation. You can either do it in each viewController that you present separately, or, if you have subclassed UITabBarController (like I have), you can add it into its viewWillAppear method. Just be aware that calling the fix right away won't help (I've tried); that's why I used the dispatch_after GCD function:
- (void)viewWillAppear:(BOOL)animated {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
});
...
}
I know this is not the cleanest way, but it's clearly bug on Apple's side, and it's likely to stay with us for a while (I assume there won't be any iOS 7.2, so we'll most likely be stuck with this until iOS 8 comes out).
It's been a while, so I'll re-iterate the issue. iOS 7 (on Device) Tab Bar becomes completely see-through on device, but works fine on Simulator. Appears to happen after hitting Back from a detail page that has hidesBottomBarWhenPushed enabled.
Setting the Tab Bar Controller > Tab Bar > Background to White Color in the Storyboard fixed it for me. This fix keeps the translucency intact.
For some reason, toggling tabBar.translucent off and on again in ViewDidAppear did not work for me.
Using Xcode 6.3.1 with Swift.
Go in your Main.storyboard and select your MKMapView to highlighted it (cf. in Navigator area you can select « Map View »). Then look carefully where is the bottom "white square": move it up the bottom bar!
In the size inspector, you can check where you place the « anchor » or view origin for this view (cf. top-left hand side in your project). This explains why it’s ok for iphone 5 which has a bigger height screen.
I am pushing a viewController onto the UINavigationController with animation, and the controller being pushed on is basically doing something like:
--- app delegate:
[((UINavigationController *)window.rootViewController) pushViewController:initialController animated:YES];
--- initial controller:
- (void)viewDidLoad {
[super viewDidLoad];
if (self.shouldSkipThisController) {
SomeOtherViewController *someOther = [[SomeOtherViewController alloc] init];
[self.navigationController pushViewController:someOther animated:NO];
}
}
This is causing some CRAZY behavior which I don't understand at all. Basically, it seems like the navigation items set on SomeOtherViewController are being covered up by some strange other button that has the name of the title in a back button. It looks like although SomeOtherViewController is setting it's own left and right navigation items, they are covered up by the "default" back button--- and then if I tap on that back button, then just the navigation bar at the top animates-- and THEN SomeOtherViewController's navigation items are then there.
The only thing I could find that sort of worked was to either 1) not animate the push of the initial view controller in the app delegate, or 2) move the shouldSkipThisController condition into viewDidAppear: method.
However, neither of those options are ideal... Any help could be greatly appreciated.