I am using ZUUIRevealViewController. I have got one UITableview each in the frontview controller and the rearviewcontroller.Depending on the values passed, I have to dynamically reload the UITableview in both controllers. How can I pass values to and fro from frontview controller to rearview controller and vice versa?
The code that I am using for navigating is
[(ZUUIRevealController *)self.navigationController.parentViewController revealToggle:nil];
and for going back
RevealController *revealController = [self.parentViewController isKindOfClass:[RevealController class]] ? (RevealController *)self.parentViewController : nil;
[revealController revealToggle:self];
Related
Ok so I'm trying to present a view controller from a UIView like this:
CSCamera *camera = [CSCamera cameraFromYamlNode:answer forView:view];
[view addSubview:camera.view];
Now my CSCamera view is basically a view controller that does some custom managing of UIImagePickerController (custom overlays and things). In order to do this I have a method showCamera() that is called to modally present the picker after I add camera.view as a subview:
[camera showCamera];
However I am getting this error:
Warning: Attempt to present <UIImagePickerController: 0x1eda8d90> on <CSCamera: 0x2008e4d0> which is already presenting (null)
Is what I'm trying to do possible?
You have a big structural problem.
CSCamera *camera = [CSCamera cameraFromYamlNode:answer forView:view];
[view addSubview:camera.view];
Adding a subview that belongs to a different view controller is unsupported. I think it's the root cause of all your woes.
I've got a SVC setup which works well. The master and detail views of the SPC are both UINavigationControllers, with separate root view controllers each.
My application works perfectly. I can start it up in either portrait or landscape mode and everything works as it aught to. The 'master' popup button is visible in portrait mode but hidden in landscape mode. Both master and detail planes animate and rotate properly, there is no popping or weird animation artifacts present, and everything stretches properly. 100% satisfaction per spec.
Issues arise when I replace the detail view controller. Since we cannot replace the root node of a uinavi controller, what I do is create a brand new UINavigationController, assigning it the new view I want in the detail view. I do this because the views in the detail view can do 1-2-3 levels deep, but I need to be able to assign unique 'root' views (eg I need to be able to completely replace the root UINavigationController).
The code looks like this:
self.detailViewController = [[SomeNewController1of3 alloc] initWithNibName:#"SomeNewController1of3" bundle:nil];
self.splitViewController.delegate = self.detailViewController;
UINavigationController *newNC = [[UINavigationController alloc] initWithRootViewController:self.detailViewController];
self.splitViewController.viewControllers = #[navigationController, newN];
First, I create the new viewcontroller, whatever it may be. I then set the splitviewcontroller's delegate to = the newly created viewcontroller (so that willHideViewController, etc fires). Then I create the a navicontroller to house the newly created viewcontroller, so that it can push and pop from it. And finally, I replace the second (detail) view of the split view controller with my new navi controller.
Again, this plan works flawlessly when I start in landscape.
When I start in portrait, these are the anomalies I've noticed:
All popups (alert boxes, the master view, etc) have weird rotations and flip out from an awkward spot when they are shown. It's almost as if it rotates these popups right as they're displayed, instead of having them simply 'slide' out of their correct locations.
When the master view is displayed, after doing the weird rotation describes above, it disappears completely for an instant (leaving a black, empty region) then reanimates to it's original location.
Until I complete a device rotation, the 'master' button on the detail view controller which displays the popup for the master view is not shown. After confirming with breakpoints, I've indeed concluded that willHideViewController is Not being called by my above method.
What I don't get is why everything behaves flawlessly when I start in landscape, but all of these errors arise in portrait? All of my views actually have a default orientation set to portrait in IB, and are scale to fit. Also it's not like they're crazy interfaces, they are all just stock tableviews.
Have any of you encountered this issue or found a method around it?
Firstly, the UISplitViewController delegate should be a top level object like your App Delegate, not a view controller the split controller is showing.
Secondly, to answer your question, to replace a showing detail view controller (i.e. pushed on the master nav) in portrait you can make use of a split controller delegate method:
AppDelegate.m
- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender{
if(!splitViewController.isCollapsed){
return NO;
}
UINavigationController *masterNav = splitViewController.viewControllers.firstObject;
if(![masterNav.topViewController isKindOfClass:UINavigationController.class]){
return NO;
}
UINavigationController *existingDetailNav = (UINavigationController *)masterNav.topViewController;
UINavigationController *newDetailNav = (UINavigationController *)vc;
existingDetailNav.viewControllers = #[newDetailNav.viewControllers.firstObject];
return YES;
}
You might be wondering why we don't just replace the master nav stack. Well the problem is the split view controller preserves the detail view controller from the last time showDetail that went through its default behavior. So if we were in portrait, tapped on a cell to show detail, then replaced the detail, then navigate back then upon rotating to landscape the old detail will show on the right and not the new one. By replacing the detail nav stack with the new detail controller as above this solves this because although the split is showing the preserved detail nav it now contains the new detail.
I find it is easier to subclass the SplitViewController. From there, you can easily swap out the the detail adding a navController for those that need it.
Subclass UISplitViewController and set your root splitViewController to that class. Then add this method to your UISplitViewController subclass:
-(void)setDetailControllerTo:(UIViewController *)detailController withNavControllerTitle:(NSString *)title {
[detailController view]; // this line forces the viewDidLoad method to be called
if (title) {
UINavigationController *navController = [[UINavigationController alloc] init];
[navController pushViewController:detailController animated:YES];
detailController.title = title;
NSArray *viewControllers=#[self.mainController.viewControllers[0],navController];
self.mainController.viewControllers = viewControllers;
} else {
NSArray *viewControllers=#[self.mainController.viewControllers[0],detailController];
self.mainController.viewControllers = viewControllers;
}
}
To call this method do something like this from the master view controller in the tableView:didSelectRowAtIndexPath: method
FixedSplitViewController *splitController = (FixedSplitViewController*) self.splitViewController;
CurrentEventViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"CurrentEventViewController"];
// add any setup code here
[splitController setDetailControllerTo:controller withNavControllerTitle:#"Current Event"];
If you wish to keep the master view visible in portrait rotation, add this method to the SplitViewController subclass:
-(BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation {
return NO;
}
i don't know if anyone is using this open source library for replacing UIPopovercontroller for an iPhone.
i'm trying to deploy the FPPopover into my project, everything is working like i want, but the problem is that i'm not able to return any value to my ViewController.
i'm trying this in didSelectRowAtIndexPath
myParentViewController *parentController =(myParentViewController*)self.parentViewController;
but the problem is that self.parentViewController is (null)
i have also another problem, how can i dismiss the FPPopoverController from within didSelectRowAtIndexPath.
I dismissed the view by adding a popoverView property to the table view controller that is popping up (in this case ATableViewController), and then assigning the FPPopoverViewController to that property. Like this:
ATableViewController *aTableViewController = [[ATableViewController alloc] init];
FPPopoverController *aPopoverController = [[FPPopoverController alloc] initWithViewController:aTableViewController];
aPopoverController.delegate = aTableViewController;
aTableViewController.popoverView = aPopoverController;
Then in didSelectRowAtIndexPath of aTableViewController you can just call:
[self.popoverView dismissPopoverAnimated:YES];
If you are trying to return values to the "parent"...since the parentViewController property is null here, you can just make your own property for it (let's call it "parentView"). So when setting up the above you would use:
aTableViewController.parentView = self;
Then you can access any of the properties of the parentView and return values from the aTableViewController that popped up. A bit of a workaround, but that's what I did...hope it helps!
I have a UITabBar with 5 tabs. I only wish to enable autorotation for a UIViewController that gets pushed onto the stack deep inside tab #3. So to be clear: tap UITabBar item 3, and you get tabbar item #3's root UIView, which should not autorotate. Tap and get another UIViewController pushed onto the stack (via a UINavigationController). Tap again, and get another UIViewController pushed onto the stack. Only here should this UIView autorotate.
The other 4 tabs should not rotate at all--not the root view of the tabs, nor any of the child views of the tabs.
Can someone tell me what approach I should use? I read that every single tab needs to respond "YES" to willAutorotateToInterfaceOrientation.
In each view's shouldAutorotate..., you could call a method in the root view controller that checks what is currently being displayed. If the deep-level view for tab 3 is on display, it will return YES, otherwise NO, and the views will, in turn, return the same.
Edit -- more detail per user798719's request:
Your root view controller knows which view is on display. You add a method to the root view controller - (BOOL) isDeepLevelTab3Displayed;. The method checks whether the deep-level view for tab 3 is on display and, if so, returns YES, otherwise returns NO.
Each sub view controller’s shouldAutorotate… method will get a ref to the root controller so that it can call isDeepLevelTab3Displayed.
If you’re using a navigation-style controller, you can get the ref like this (self is the sub controller):
NSArray *arrayOfControllers = [self viewControllers];
UIViewController *rootController = [arrayOfControllers objectAtIndex:0]; // per UIViewController class ref, root controller is at index 0
Or you could get anything in your project like this:
YourProjectAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
UIViewController *rootController = appDelegate.rootController; // or appDelegate.intermediateClass1.intermClass2.rootController — however you set up your project
So every sub controller would do this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
UIViewController *rootController = [[self viewControllers] objectAtIndex:0];
return [rootController isDeepLevelTab3Displayed];
}
Therefore, every subcontroller would return YES when autorotation should happen, fulfilling the requirement you mention at the end of your question.
However, if all your subcontrollers are instances of UINavigationController, you could determine which view is currently on display directly, by calling visibleViewController. Then you just need a way of checking its identity.
You could check the controller’s nibName or title, for example, against a constant, or add an integer property intControllerIdentity to all your controllers and set them in the controller’s initWithNibName…
The integer-property scheme might be best, because it won’t be affected should you later change the nibName or title.
You’d add constants to some class whose h file is imported by all the controllers (or, if all the controllers are instances of the same class, put these constants in that class’s h file):
#define kFooController 1
#define kBarController 2
#define kRotatableController 3
And you’d set it like this:
self.intControllerIdentity = kRotatableController;
And check it like this:
if (self.intControllerIdentity == kRotatableController)
Hope that helps. But evaluate this added detail with a critical eye; I have worked with autorotation but not yet with navigation controllers.
I have one main view where I display an image, in the method viewDidLoad:
ballRect = CGRectMake(posBallX, 144, 32.0f, 32.0f);
theBall = [[UIImageView alloc] initWithFrame:ballRect];
[theBall setImage:[UIImage imageNamed:#"ball.png"]];
[self.view addSubview:theBall];
[laPalla release];
Obviously, the value of posBallX is defined and then update via a custom method call many times in the same class.
theBall.frame = CGRectMake(posBallX, 144, 32, 32);
Everything works, but when I go to another view with
[self presentModalViewController:viewTwo animated:YES];
and come back with
[self presentModalViewController:viewOne animated:YES];
the image is displayed correctly after the method viewDidLoad is called (I retrieve the values with NSUserDefaults) but no more in the second method. In the NSLog I can even see the new posBallX updating correctly, but the Image is simply no more shown...
The same happens with a Label as well, which should print the value of posBallX.
So, things are just not working if I come back to the viewOne from the viewTwo... Any idea???????
Thanks so much!
You should use dismissModalViewControllerAnimated: to switch back to viewOne from viewTwo instead of trying to present viewOne modally.
Also note that viewDidLoad is called only once - after the view controller's view is loaded into memory. If you want to perform an action once a view comes back on screen, you should do so in viewWillAppear:.
Both of these points are discussed in the UIViewController class reference and in the View Controller Programming Guide.