Is there a way to use one of this preview controls with UISplitViewController's detail view..
I'm trying to preview Documents of the application, and made the file browser part.. But the other part still eludes me..
Whatever I did to show preview on a detail view on SplitViewController ended with failure.. Could you help me? How could I achieve this functionality?
I did this by having my detail view controller embedded in a uinavigationcontroller. After creating the QLPreviewController I just pushed the view controller on to the navigation controller.
In the detail view controller:
QLPreviewController *previewController = [[QLPreviewController alloc] init];
[previewController setDataSource:self];
[previewController setDelegate:self];
[self.previewItem setTitle:item.name];
[self.navigationController pushViewController:previewController animated:NO];
The detail view controller also uses the QLPreviewControllerDelegate
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller {
return 1;
}
- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index {
return self.previewItem;
}
Related
I'm building an app that currently has 3 ViewControllers. One of them is used after a successful login so is not relevant in this question.
I'm using a mixture of Storyboards and building things programmatically when I find Storyboards do not give me the fine control that I need.
The first ViewController is built in my 'MainStoryboard'. It has a login form and an info button at the bottom. I link it up the my AppDelegate by doing the following inside didFinishLaunchingWithOptions:
ViewController *viewController = (ViewController *)self.window.rootViewController;
Because I wanted to force rendering of a UIWebView (another story) I create the second view programmatically. I do the following inside didFinishLaunchingWithOptions:
infoViewController = [[InfoViewController alloc] init];
[infoViewController view];
Inside both of my ViewControllers I setup a link to appDelegate as below:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
I have an info button in my first ViewController that takes you to the infoViewController. It calls the following code when tapped:
appDelegate.infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:appDelegate.infoViewController animated:YES];
The above works just fine for me, flips over the screen and shows the InfoViewController.
On my InfoViewController I have a button that should take you back to the login page, I have tried all sorts to get this to work but it just crashes my app. Nothing seems to work. I have tried the following:
appDelegate.viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:appDelegate.viewController animated:YES];
and
[self.navigationController popToRootViewControllerAnimated:YES];
and
[self.navigationController popViewControllerAnimated:YES];
and
[self.navigationController popToViewController:appDelegate.viewController animated:YES];
I suspect the last 3 might be more to do with when you have a navigation view controller and you want to go back to the root? I'm not sure, but either way it does not work. I had this working using storyboards previously so I'm sure it ought to be easy! As mentioned I switched to making the infoViewController programmatically so that I could force the UIWebView to render before the view appeared.
Any help much appreciated.
You can do with:
[self dismissModalViewControllerAnimated:YES];
You should use this.
[self dismissModalViewControllerAnimated:YES];
You should use a main controller for switching between your other view controllers. Change the view of your root controller to one of your other view controllers (apply animations as usual if needed). Hold a pointer to your root controller in your other view controllers and call self.rootController.view = <desired_controller_instance>.view
I think the way you're presenting your InfoViewController is wrong. Do it the following way:
In your ViewController, create an action for the info button.:
- (IBAction)infoButtonTapped:(id)sender
{
InfoViewController *infoViewController = [[InfoViewController alloc] init];
infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:infoViewController animated:YES];
}
And in your InfoViewController, in the action of your button that should take you back write this:
- (void)takeBackToViewController
{
[self dismissModalViewControllerAnimated:YES];
}
Hope it works.
Also in presented controller you can use this
if(self.parentViewController)
[self.parentViewController dismissModalViewControllerAnimated:YES];
else
[self.presentingViewController dismissModalViewControllerAnimated:YES];
To dissmiss current controller.
I have an RSS parser in a UITableView that pushes to the detail view when one of the rows is selected. I had it working fine in the old UI format of using Nib files, but I wanted to transfer everything to UIStoryboard. I learned that UIStoryboards and nibs were compatible, so I decided I would keep the same code, but put the UITableView in the UIStoryboard and have the detail view be its own nib. I linked everything up and it should be working, and its not giving me any errors, but its not. Is there anything that I missed, or are storyboards and nibs not compatible at all.
Edit:
- (id)initWithItem:(NSDictionary *)theItem {
if (self == [super initWithNibName:#"RssDetailController" bundle:nil]) {
self.item = theItem;
self.title = [item objectForKey:#"title"];
}
return self;
}
Are you pushing from a UIViewController in UIStoryboard to a NIB file?
If so check out this sample project that pushes from storyboard to a NIB:
// in a navigation controller
// to load/push to new controller use this code
// this will be next screen
DetailsViewController *detailsViewController = [[DetailsViewController alloc ]init];
[self.navigationController pushViewController:detailsViewController animated:YES];
// to go back or pop controller use this
// now it will send back to parent screen
[self.navigationController popViewControllerAnimated:YES];
this is a newbie question.i ve created a grouped tableview .on clicking the tableview cell it navigates to a new view.but i m unable to create a back button.I even added a navigation bar in the second view of the nib file.but its of no effect..could you guys help me out..below is the screenshot and code of the first view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
if (indexPath.row==0) {
self.dvController1 = [[FirstView alloc] initWithNibName:#"FirstView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController1 animated:YES];
}
if (indexPath.row==1) {
self.dvController2 = [[Tab4 alloc] initWithNibName:#"Tab4" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController2 animated:YES];
}
}
In the presented controller add a button with an IBAction in it:
- (IBAction)back:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
And make sure that you have a navigationController indeed (meaning that your application needs to be navigation oriented, meaning that you need to instantiate the navigationController property in the application delegate)
In your second view .put this code in viewDidLoad method
self.navigationItem.leftBarButtonItem.title = #"Back";
just hide the bar in the viewWillAppear method & unhide the bar in viewWillDisAppear methods of the tableViewController class. By using
self.navigationController.navigationBarHidden = YES/NO;
In my UISplitViewController application, I have
RootViewController - view controller in the left pane.
DetailViewController - view controller in the right pane.
When one item (which is in a UITableView) in RootViewController is tapped, new view controller will be set as the following shows:
[detailViewController setViewControllers:[NSArray arrayWithObjects:newViewController, nil] animated:animated];
//detailPane is my DetailViewController
All works pretty well in landscape mode. However, I can't make the UISplitViewController work as what I want in portrait mode, that is, the RootViewController's popover button does not appear appropriately in my DetailViewController when I launch and use the application in portait mode.
When I launch the app in portrait mode, the popover button appears appropriately. But after tapping one item in the popover and a new view controller has been set on detailViewController, the button disappeared. I have to rotate the device to landscape and then back to portrait again to make the button appear again.
I set my UISplitViewController's delegate in my application's AppDelegate as follows:
self.splitViewController.delegate = self.detailViewController
And here is my UISplitViewControllerDelegate implementation
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc {
NSLog(#"Will hide view controller");
barButtonItem.title = #"Menu";
[self.navigationItem setLeftBarButtonItem:barButtonItem];
self.popoverController = pc;
}
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
NSLog(#"Will show view controller")
NSMutableArray *items = [self.navigationItem.leftBarButtonItems mutableCopy];
[items removeAllObjects];
[self.navigationItem setLeftBarButtonItems:items animated:YES];
[items release];
self.popoverController = nil;
}
Any hint or help is greatly appreciated.
Thanks.
Just came up with a new solution.
Subclass UINavigationController and implement UISplitViewControllerDelegate. Set an instance of this class as the right ViewController of the splitViewController. Everytime you want to change the detail view controller from the master
NewDetailViewController *newDetailVC = ....// Obtain the new detail VC
newDetailVC.navigationItem.leftBarButtonItem = [[[[self.splitViewController.viewControllers objectAtIndex:1]topViewController]navigationItem ]leftBarButtonItem]; //With this you tet a pointer to the button from the first detail VC but from the new detail VC
[[self.navigationController.splitViewController.viewControllers objectAtIndex:1]setViewControllers:[NSArray arrayWithObject:newDetailVC]]; //Now you set the new detail VC as the only VC in the array of VCs of the subclassed navigation controller which is the right VC of the split view Controller
This works for me and I can avoid defining a hole protocol and setting the master as the delegate, which is a big trade off. Hope it helps.
If you still need it:
http://developer.apple.com/library/ios/#samplecode/MultipleDetailViews/Introduction/Intro.html
What I did to my source (I had similar setup to you) to fix it:
I have the master viewcontroller (UITableViewController in my case) be the delegate of the UISplitViewController. In the two delegate methods for UISplitViewControllers (so this would be in your master viewcontroller implementation) you would save the popupviewcontroller and the barbuttonitem in your class. Now, if you change your details viewcontroller, you do:
self.viewControllers = [NSArray arrayWithObjects:[self.viewControllers objectAtIndex:0], newDetailsViewController, nil];
UIViewController <SubstitutableDetailViewController>*vc = (UIViewController <SubstitutableDetailViewController>*)newDetailsViewController;
[vc invalidateRootPopoverButtonItem:_tableViewController.rootPopoverButtonItem];
[_createReportViewController showRootPopoverButtonItem:_tableViewController.rootPopoverButtonItem];
where we have
#protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
the delegate that each of your detailsViewControllers should adhere to. You would implement like this:
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
self.navigationItem.leftBarButtonItem = barButtonItem;
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
self.navigationItem.leftBarButtonItem = nil;
}
Let me know if this helps you.
I liked Nekto's solution, but it misses one key problem.
It's not clear what action: selector will cause the UISplitViewController to show the MasterViewController in a popover. When I finally figured this out, by examining the BarButtonItem in the debugger, I realized why it was so tricky to figure this out: the action: selector isn't documented anywhere in Apple's iOS SDK. Oops.
Try this:
UIBarButtonItem *showListView = [[UIBarButtonItem alloc] initWithTitle:#"List" style:UIBarButtonItemStyleBordered target:[self splitViewController] action:#selector(toggleMasterVisible:)];
[[detailViewController navigationItem] setLeftBarButtonItem:showListView];
You may want to surround this code with a conditional that checks the window is in in portrait mode, such as if ([self interfaceOrientation] == UIInterfaceOrientationPortrait)
When you are setting new view controllers placed on navigation stack, probably, all navigation buttons are reset. You can manually add appropriate buttons after changing navigation stack.
For example, you can pick code from - (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc where default popover controller button is created:
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:#"Menu" style:UIBarButtonItemStyleBordered target:self action:#selector(appropriateSelector)];
[self.navigationItem setLeftBarButtonItem:barButtonItem];
self.popoverController = pc;
I have a navigation based app with a navigation bar, but there are a few instances where instead of pushing a view controller onto the stack, I need to present the view controller modally. The problem is that when I dismiss the modal view controller, everything functions as expected except that the navigation bar is hidden and the (parent view) has been resized, which is the expected behavior according to the docs. So I figured I could simply call a built-in method to unhide the navigation bar. I have already tried
[self.navigationController setNavigationBarHidden:NO];
as well as the animated version without success.
The documentation talks about this in the method
presentModalViewController: animated:
in the discussion section where it says,
On iPhone and iPod touch devices, the view of modalViewController is always presented full screen" and "Sets the modalViewController property to the specified view controller. Resizes its view and attaches it to the view hierarchy."However, the docs didn't clue me in as to how to undo this process after dismissing a modal view.
Has anyone else experienced this and found a solution?
Edit: I am having this same problem, so instead of asking my own question I am sponsoring a bounty on this one. This is my specific situation:
In my case, I am presenting an Image Picker in a Modal View Controller, over a Navigation Controller:
-(void) chooseImage {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
imagepicker = [[UIImagePickerController alloc] init];
imagepicker.allowsEditing = NO;
imagepicker.delegate = self;
imagepicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagepicker.navigationBar.opaque = true;
imagepicker.wantsFullScreenLayout = NO;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if (self.view.window != nil) {
popoverController = [[UIPopoverController alloc] initWithContentViewController:imagepicker];
[popoverController presentPopoverFromBarButtonItem:reset permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
} else {}
} else {
[self.navigationController presentModalViewController:imagepicker animated:YES];
}
}
}
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self.popoverController dismissPopoverAnimated:true];
} else {
[self.navigationController dismissModalViewControllerAnimated:YES];
}
//Save the image
}
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self.popoverController dismissPopoverAnimated:true];
} else {
[self.navigationController dismissModalViewControllerAnimated:YES];
}
}
Make sure you a presenting AND dismissing the modalViewController from the UINavigationController, like so:
// show
[self.navigationController presentModalViewController:vc animated:YES];
// dismiss
[self.navigationController dismissModalViewControllerAnimated:YES];
If your view controller is actually on the UINavigationController's stack then this is the correct way to handle the presentation and dismissal of the modal view controller. If your UINavigationBar is still hidden, there is something else funky going on and we would need to see your code to determine what is happening.
Edit
I copied your code into an app of mine and the UIImagePickerController successfully presented and dismissed and my UINavigationController's UINavigationBar was still there. I truly believe that the problem lays elsewhere in your architecture. If you upload a zip w/ an example project I will take a look.
Simply try following code it will work
SettingsViewController *settings = [[SettingsViewController alloc] init];
UINavigationController *navcont = [[UINavigationController alloc] initWithRootViewController:settings];
[self presentModalViewController:navcont animated:YES];
[settings release];
[navcont release];
One need to present the navigation controller in order to have navigation bar on the presented controller
I think I've seen this behavior when presenting a view controller on the wrong VC. Are you calling presentModalViewController on the navigation controller or the individual VC?
Try calling it from the navigationController if you aren't already.
[self.navigationController presentModalViewController:myVC animated:YES];
If you present a controller as model, View controller will appear to total view.
If you want to access the navigation controller properties over the model view, You need to create another navigation controller reference and it continues as previous.
This may be useful for you.
Check this out. This is Apple's Documentation under UIViewController Class Reference:
It clearly mentions that modal view always presents in full screen mode, so it is obvious that navigation bar will be hidden. So put the seperate navigation bar on modal view to navigate back.
presentModalViewController:animated:
Presents a modal view managed by the given view controller to the user.
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
Parameters
modalViewController
The view controller that manages the modal view.
animated
If YES, animates the view as it’s presented; otherwise, does not.
Discussion
On iPhone and iPod touch devices, the view of modalViewController is always presented full screen. On iPad, the presentation depends on the value in the modalPresentationStyle property.
Sets the modalViewController property to the specified view controller. Resizes its view and attaches it to the view hierarchy. The view is animated according to the transition style specified in the modalTransitionStyle property of the controller in the modalViewController parameter.
Availability
Available in iOS 2.0 and later.
Hope this helps you understand that hiding the whole view along with navigation controller is default behaviour for modal view so try putting a seperate navigation bar in modal view to navigate.
You can check it further on this link
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
AddContactVC *addController =[self.storyboard instantiateViewControllerWithIdentifier:#"AddContactVC"];
UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:addController];
[self presentViewController:navigationController animated:YES completion: nil];
working for me shows navigation bar
Emphatic and Devin –
As I started reading through the Apple docs to get familiar with the problem, I noticed that the method you're using, presentModalViewController:animated:, appears to be deprecated in favor of presentViewController:animated:completion:. Perhaps you should try to use that method instead.
For your convenience, take a look for yourself:
presentModalViewController:animated: reference
I'll try to put together a quick test program to see whether what I've said above is actually true. But give it a shot – maybe it'll help!
Xcode has a template that does pretty close to what you're doing. from the results, i don't think you should be attempting to perform [self.navigationController presentModalViewController:vc] and [self.navigationController dismissModalViewControllerAnimated:] , but rather simply [self presentModalViewController:] and [self dismissModalViewControllerAnimated:] .
to see how the template does this for yourself, you can use the new project wizard in xcode 4.3 . perhaps it will provide some guidance:
from that choice, choose Next, then give your test project a name, choose "Universal", turn off automatic reference counting, hit next, save where you want it.
now, click on the target and switch the deployment target to 4.3 (or 4.0 if you prefer) for your testing purposes, and switch to your device or the iOS 4.3 simulator .
finally, substitute the following code in applicationDidFinishLaunching:withOptions: in the created AppDelegate.m:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.mainViewController = [[[MainViewController alloc] initWithNibName:#"MainViewController_iPhone"
bundle:nil] autorelease];
} else {
self.mainViewController = [[[MainViewController alloc] initWithNibName:#"MainViewController_iPad"
bundle:nil] autorelease];
}
UINavigationController* navigationController
= [[UINavigationController alloc] initWithRootViewController:self.mainViewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
now, when i run this, it doesn't hide the navigationBar. and in the created MainViewController.m from the template, you'll see how it presents the modal view controller and dismisses it from the controller itself and not from the navigation controller. for good measure, to make the template code more like your own, go into MainViewController.m and delete the line that sets the modal view controller transition style ...
(of course, in iOS 5, with storyboards, the same thing can all be accomplished with modal segues ... which is how i've done this for apps that i'm not supporting for pre-5.0 that present a modalViewController in this fashion.)
One of the best solution it to use this Category MaryPopin
https://github.com/Backelite/MaryPopin