I'm creating an app that has some UIBarButton items, some of which will launch a UIPopoverController when pressed. I'd like for this to disable anything from being able to be interacted with, which mostly happens by default. I've noticed, however, that other UIBarButtonItems within the same toolbar will still be active while the popover is active. I've tried to add:
[_popOver setPassthroughViews:nil];
prior to showing it, but the UIBarButtonItems are still able to be pressed while the pop over is shown. I realized I could disable the buttons, but I'd rather not have to do this as I'd have to introduce all kinds of unnecessary state while each kind of pop-over is open. Is there any way to have the pop-over be dismissed when anything is selected outside the pop-over (including other UIBarButtonItems)?
Basic code to repro the problem:
- (IBAction)rightButtonPressed:(id)sender {
UIViewController *vc = [[UIViewController alloc] init];
_popOver = [[UIPopoverController alloc] initWithContentViewController:vc];
[_popOver setPassthroughViews:nil];
[_popOver presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
- (IBAction)leftButtonPressed:(id)sender {
NSLog(#"Why am I active while pop-over is visible?");
}
Add both bar button items to the same navigation bar.
I'm an idiot, figured out the solution moments after posting this. It seems the call to presentPopoverFromBarButtonItem automatically adds the navigation bar to the passthroughviews. Since I was clearing out before and not after presenting the UIPopoverView, it was getting added back. A simple change of the order of the calls fixes the problem.
- (IBAction)rightButtonPressed:(id)sender {
UIViewController *vc = [[UIViewController alloc] init];
_popOver = [[UIPopoverController alloc] initWithContentViewController:vc];
[_popOver presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
//Call this *AFTER* presenting the popover
[_popOver setPassthroughViews:nil];
}
Related
When I have a "loading" root view controller when the app starts which will determine to load either the slide menu controller or another controller, the menu does not work. It is visible, and the animations work just fine, only all touches are disabled.
I've distilled my setup to this:
In the app delegate
self.window.rootViewController = [[TestViewController alloc] init];
And in the testViewController viewDidAppear:
SlideNavigationController *slideNavigationController = [[SlideNavigationController alloc] initWithRootViewController:[[ARootViewController alloc] init]];
slideNavigationController.leftMenu = [[UINavigationController alloc] initWithRootViewController:[[MenuViewController alloc] init]];
slideNavigationController.menuRevealAnimator = [[SlideNavigationContorllerAnimatorScaleAndFade alloc] initWithMaximumFadeAlpha:0.6f fadeColor:[UIColor darkGrayColor] andMinimumScale:.8];
slideNavigationController.enableSwipeGesture = NO;
slideNavigationController.view.layer.shouldRasterize = NO;
[self presentViewController:slideNavigationController: animated:YES callback:nil];
But then the menu does not respond to touches. If the slide navigation controller is the root view controller in the app delegate the menu does work correctly. It is really a matter of that the slide navigation controller must be the apps root controller. Is there a workaround or fix for this?
For others viewing this thread, implement SlideNavigationControllerDelegate and add below function in every controller that you do not wish to show side menu icon.
And most importantly it should be the root view controller in app delegate, otherwise it won't work.
Refer to documentation of developer here.
- (BOOL)slideNavigationControllerShouldDisplayLeftMenu
{
//or no based on your preference
return YES;
}
I am trying to display a simple iPad popover which contains a navigationController with a tableView.
popover -> navigation controller -> view controller -> table view.
I do need the navigationController because on touching the cells I want to push another viewController (within that same popover).
Without the navigation controller, everything is fine.
But as soon as I put the viewController inside a navigationController, the tableView stops responding (didSelectRow doesn't get called). I suppose something is wrong with my delegates but I just can't work it out.
. The navigationController responds fine (I can hit a button I have in the top bar)
. The buttons that are IN the cells respond fine.
. If I touch down and hold on a cell it gets highlighted, but not selected.
UPDATE: I just found out that if I hold the cell down for at least a second, the delegate is called when I release it. any less than that and it is never called...???
Here is the code use:
ModalViewController* controllerWithTable = [[self storyboard] instantiateViewControllerWithIdentifier:identifier];
UINavigationController* navigationController = [[UINavigationController alloc] initWithRootViewController:controllerWithTable];
UIPopoverController* popover = [[UIPopoverController alloc] initWithContentViewController:navigationController];
popover.delegate = self;
[popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
If you are using a popoverController to show a table view, you don't need to embed it in a navigation Controller, Instead make a different Viewcontroller with the table view and just shoe that inside a popover controller .I used it somewhat like this..
Make a global reference for UIPopoverController in your app delegate,
//in your Appdelegate.h file declare this
#property(strong, nonatomic) UIPopoverController *popOverForTableView;
Now In the controller which you want to show the PopOver view use this,
TableViewCOntroller* popoverContent = [[TableViewCOntroller alloc] init];
NSString *identifier=#"tableVC"
popoverContent =[[UIStoryboard storyboardWithName:#"Main"
bundle:nil]
instantiateViewControllerWithIdentifier:identifier];
popoverContent.preferredContentSize = CGSizeMake(330, 280);
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
appDelegate. popOverForTableView = [[UIPopoverController alloc]initWithContentViewController:popoverContent];
appDelegate.popOverForTableView.delegate = self;
appDelegate.popOverForTableView.backgroundColor=[UIColor blackColor];
[appDelegate.popOverForTableView presentPopoverFromRect:self.date.frame inView:self.view permittedArrowDirections:(UIPopoverArrowDirectionUp) animated:YES];
You can dismiss it accordingly…,…see if this Helps..
Ok I found the answer there: https://stackoverflow.com/a/18159463/3562952
The tableView was not irresponsive, it was deceptively responding only after a 1-3 seconds hold down.
I had a tap responder on the parent view that was capturing the tap. I am now removing it when displaying the popover and putting back in on dismissal.
I was googling for the wrong symptoms :)
I open a popOver with a view(DetailView) in a view(MapView). it works fine.
But in my detail view has a button(feedback).so i want to push the another view(feedbackform)on btton clicked.
I tried but nothing is Happened.
Can i push the view inside the popover?
My code is as follow:
// MapView.m
detailsView *popUp=[[detailsView alloc] initWithNibName:#"detailsView_ipad" bundle:nil];
popView = [[UIPopoverController alloc]initWithContentViewController:popUp];
popView.delegate =self;
[popView setPopoverContentSize:CGSizeMake(600, 500)];
[popView presentPopoverFromRect:control.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
//Detailview.m
-(IBAction)openFeedbackForm:(id)sender {
fbView = [[deatailsFeedback alloc]
initWithNibName:#"deatailsFeedback_ipad" bundle:nil];
[self.navigationController pushViewController:fbView animated:YES];
}
To achieve this your detailsView should be a Navigation controller with a root controller to the original detailsView.
This way when you pop the navigationController, you can perform push from your detailsView and that would only affect the popOver view
detailsView *popUpView=[[detailsView alloc] initWithNibName:#"detailsView_ipad" bundle:nil];
UINavigationController *popUpNavController = [[UINavigationController alloc] initWithRootViewController:popUpView];
popView = [[UIPopoverController alloc]initWithContentViewController:popUpNavController];
popView.delegate =self;
[popView setPopoverContentSize:CGSizeMake(600, 500)];
[popView presentPopoverFromRect:control.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
//Detailview.m
-(IBAction)openFeedbackForm:(id)sender {
fbView = [[deatailsFeedback alloc]
initWithNibName:#"deatailsFeedback_ipad" bundle:nil];
[self.navigationController pushViewController:fbView animated:YES];
}
If I understand your code correctly, openFeedForm IBAction method is in Detailview.m?
Meaning the first part of the code is in a different class than the one at the bottom?
If so, since Detailview itself is not in a navigationController, it will not push anything to its non-existant navigation controller.
What you want to do is have MapView push the new view in its navigationController.
Side note: since you are setting the delegate of the popUp in MapView as (self) the IBAction method should be defined in MapView
(This is assuming my first statement about understanding your code is correct)
I am developing an iPad/Universal application, and I am facing the problem of handling a UINavigationController as the main detail view in a UISplitViewController. What I want to know is how to add the default side controller button to the detail controller when in landscape orientation.
Definition
The split view controller has been defined this way:
splitViewController = [[UISplitViewController alloc] init];
SideController *root = [[[SideController alloc] init] autorelease];
DetailController *detail = [[DetailController alloc] init];
InserisciDatiController *calcolo = [[[InserisciDatiController alloc]
initWithNibName:#"InserisciDatiNuovi"
bundle:[NSBundle mainBundle]]
autorelease];
UINavigationController *rootNav = [[[UINavigationController alloc] initWithRootViewController:root]autorelease];
UINavigationController *calcoloNav = [[[UINavigationController alloc] initWithRootViewController:calcolo] autorelease];
splitViewController.viewControllers = [NSArray arrayWithObjects:rootNav, calcoloNav, nil];
splitViewController.delegate = detail;
and later on I release all the releasable objects.
I am using the SideController as a sort of index for the detail controller. It has a table view, and clicking each row I update the main view controller of the detail. Each new controller is always an instance of UINavigationController.
Update the detail
myAppDelegate *delegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
UINavigationController *nav = (UINavigationController *)[delegate.splitViewController.viewControllers objectAtIndex:1];
[nav setViewControllers:[NSArray arrayWithObjects:controller, nil]];
I use this piece of code to update the detail controller, when the user taps a row in the side view controller.
Handle landscape orientation
I'd like to know how to handle the landscape orientation, when I want to add the default toolbar button to display the hidden side view controller. What I am not able to do is getting the toolbar of the detail navigation controller to add the button using this method:
- (void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc
And also, when I push a new controller to the navigation controller the default back button will appear in the toolbar. In this case how should I handle the button creation?
Update
Please, do not tell me that no-one has ever had this kind of problem! How do you develop iPad apps? Sob ...
I found a way that could be useful for someone, even though I do not really think this is a clean way of handling the navigation controller.
In the split view controller delegate I implemented the splitViewController:willHideViewController:withBarButtonItem:forPopoverController: method this way:
- (void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc
{
barButtonItem.title = NSLocalizedString(#"menu", nil);
myAppDelegate *app = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
UINavigationController *nav = [app.splitViewController.viewControllers objectAtIndex:1];
UIViewController *ctrl = [nav.viewControllers objectAtIndex:0];
if (!ctrl.navigationItem.backBarButtonItem && !ctrl.navigationItem.leftBarButtonItem) {
ctrl.navigationItem.leftBarButtonItem = barButtonItem;
}
}
Here I present the bar button item that will show the popover view representing the side view controller if and only if the navigation controller is not showing the back button or another custom left button item.
Hope this helps someone!
I believe that Slava Bushtruk of Alterplay has worked out what you're looking for and used it in his APSplitViewController library.
I think the reason you haven't gotten any good answers is that it's really hard to understand your problem, i.e., your question could be clearer.
So first let me see if I've understood the problem correctly. Is the problem that you don't know how to handle the case when you've pushed something on your navigation controller and is supposed to show both the back button and the split view button?
If so, the way we've solved that problem is that the split view button is only visible in the root of the navigation controller. The side controller is usually only relevant for the detail view's root view controller anyway.
If I've misunderstood your problem or my solution isn't applicable to your project, please let me know.
EDIT: So if you insist on doing this, here's a way to do it:
toolbar = [[UIToolbar alloc] initWithFrame:(UIInterfaceOrientationIsPortrait(interfaceOrientation)) ? CGRectMake(0, 0, 768, 44) : CGRectMake(0, 0, 703, 44)];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self.navigationController.navigationBar addSubview:toolbar];
On viewWillDisappear:
[self setToolbarHidden:YES animated:animated];
and on viewWillAppear:
[self setToolbarHidden:NO animated:animated];
Now you have a toolbar that you can add anything to. Well, anything that can be added to a UIToolbar anyway, which is almost anything.
So I have a popover with a button in it. When that button is pushed, I want the popover to go away. It seems easy enough, but I can't figure it out for the life of me. The code I use to show the popover is below:
AddCategoryViewController* content = [[AddCategoryViewController alloc] init];
UIPopoverController* aPopover = [[UIPopoverController alloc]
initWithContentViewController:content];
aPopover.delegate = self;
[content release];
// Store the popover in a custom property for later use.
self.addCategoryPopover = aPopover;
[aPopover release];
[addCategoryPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
Within the addcategoryviewcontroller, I have:
-(IBAction)saveAddCategory:(id)sender {
if (rootViewController == nil)
rootViewController = [[RootViewController alloc] init];
[rootViewController.addCategoryPopover dismissPopoverAnimated:YES];
[rootViewController dismissPopover];
}
Rootviewcontroller is where the popover is being created from. Unfortunately, neither of those methods work to dismiss it. any help?
You would be seeing a warning at this line.
aPopover.delegate = self;
and if you would execute your code. The app would crash. Instead you need to do it like this.
I have
- (void)viewWillDisappear:(BOOL)anAnimated
{
[self.dPopover dismissPopoverAnimated: NO];
self.dPopover = nil;
[super viewWillDisappear: anAnimated];
}
and don't see why this wouldn't work in your case.
Your if is a bit troubling, so my guess is you aren't talking to the view you think you are. rootViewController.addCategoryPopover is probably nil, because you made a new controller.
I think I answered just a similar question with the solution I used to dismiss a popover with a UIView loaded from a MKMapView.
The use of my solution is basically the same as for any other view loading a popover.
Have a look at:
How to dismissPopoverAnimated on iPad with UIPopoverController in MKMapView (SDK3.2). I hope that solved your problem.
use NSNotificationCenter To DissmissPoperController Fro Father viewControll