I have a problem like this:
I have a root view which has a UIPopoverController and a button, when I click on that button, it present a tableView. My app display OK but now when I click in any row, the UIPopoverController still display and I want it dismiss.
Any help? Thanks!
This is my code:
ViewController.h
#import <UIKit/UIKit.h>
#import "UIPopoverIphone.h"
#import "TableViewController.h"
#interface ViewController : UIViewController <UIPopoverControllerDelegate, TableViewPopoverDelegate> {
TableViewController *popoverView;
IBOutlet UIButton *popButton;
UIPopoverController *pop;
}
#property (strong, nonatomic) UIPopoverController *pop;
+(void)hidePop;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize pop;
-(void)dealloc {
[pop release];
[super dealloc];
}
-(IBAction)showPop {
popoverView = [[TableViewController alloc] init];
popoverView.delegate = self;
pop = [[UIPopoverController alloc] initWithContentViewController:popoverView];
[pop setPopoverContentSize:CGSizeMake(100, 200)];
[pop setDelegate:self];
[pop presentPopoverFromRect:popButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
-(void)hidePop {
[pop dismissPopoverAnimated:YES];
}
....
#end
TableViewController.h
#import <UIKit/UIKit.h>
#protocol TableViewPopoverDelegate <NSObject>
-(void) dismissPopover;
#end
#interface TableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
NSMutableArray *itemsArray;
UITableView *tableView;
id<TableViewPopoverDelegate> delegate;
}
#property (nonatomic, retain) NSArray *itemsArray;
#property (nonatomic, retain) UITableView *tableView;
#property (nonatomic, assign) id<TableViewPopoverDelegate> delegate;
#end
TableViewController.m
#import "TableViewController.h"
#implementation TableViewController
#synthesize itemsArray;
#synthesize tableView;
-(void) dealloc {
[itemsArray release];
[tableView release];
[super dealloc];
}
-(void)loadView {
UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];
self.view = mainView;
[mainView release];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 100, 200) style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
}
....
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
NSLog(#"%#",[self.itemsArray objectAtIndex:indexPath.row]);
[self.delegate dismissPopover];
}
#end
With your current work flow, the ViewController have no connection with TableViewController. It looks like you are presenting the UITableViewController from the UIPopoverIphone not from the ViewController. So the delegate callback method dismissPopover needed to be implemented within the UIPopoverIphone class not the ViewController class. If you still want to dismiss the UIPopoverIphone from the ViewController, there are two options:
Using NSNotificationCenter: In the TableViewController, you can post a notification when you are ready to dismiss the popover. Then in the ViewController, you can observer that notification and dismiss the popover. In this scenario, no delegate is involved.
Setup the delegate callback from your UIPopoverIphone class and the ViewController class. So when you tap the button in the popover, it makes a callback to ViewController, you then dismiss the popover and prepare your TableViewController and present it. Here your TableViewController and the ViewController have a connection.
It appears that your root view ViewController doesn't correctly implement your TableViewPopoverDelegate. You've declared a method in that delegate called dismissPopover, but you haven't implemented it in ViewController.m.
In ViewController.m, change the hidePop function to:
-(void)dismissPopover {
[pop dismissPopoverAnimated:YES];
}
Popovers by default dismiss themselves when a tap is detected outside of their bounds.
Related
I have a UILabel in interface builder that I've connected to a property, but it's staying nil through the viewDidLoad on that view controller. I've been stepping through and as soon as the DetailViewController is initialized, the label property is there but it is nil and it never seems to be initialized.
It was working until I switched from using segues to doing pushViewController on the navigation controller.
// DetailsViewController.h
#import <UIKit/UIKit.h>
#import "TLitem.h"
#interface DetailsViewController : UIViewController
#property (nonatomic, strong) TLitem *entry;
#property (weak, nonatomic) IBOutlet UILabel *entryLabel;
#end
Then in a table view in another view controller:
// EntryListViewController.m
DetailsViewController *details = [[DetailsViewController alloc] init];
[details setEntry:entry];
[self.navigationController pushViewController:details animated:YES];
And in the viewDidLoad:
// DetailsViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor yellowColor]];
TLitem *entry = [self entry];
UILabel *label = [self entryLabel];
label.text = [entry valueForKey:#"text"];
[[DetailsViewController alloc] init] is not loading the view controller from the storyboard. It creates a new DetailsViewController, but nothing from IB will be connected. Look into -instantiateViewControllerWithIdentifier:
It will look something like
DetailsViewController *details = [self.storyboard instantiateViewControllerWithIdentifier:#"Some Storyboard Identifier You Create"];
details.entry = entry;
[self.navigationController pushViewController:details animated:YES];
edit: solved. see my comment why.. sorry this mess, not able to post an answer myself yet as a newbie..
iPad App: I have a table view and instantiate from the accessoryView a popover with another tableview. in the popover I want to select a cell and pass that index back to the rootView.
I implemented a protocol in PopoverController and conform RootViewController to it.
Why is that backPopover method in the root view not being called?
Any hint much appreciated!!
Edit: That storyboard reference points to a navigation controller. The popover itself works fine..
RootViewController.h
#import "PopoverViewController.h"
#interface rootViewController : UITableViewController <UIPopoverControllerDelegate, UITableViewDelegate, AddDelegate>
{
UIPopoverController *popOverController;
}
#property (nonatomic, retain) UIPopoverController *popOverController;
#property (nonatomic) PopoverContent *popoverContent;
RootView.m
-(void) backPopover:(int)index
{
NSLog(#"index sent:%i", index);
[popOverController dismissPopoverAnimated:YES];
}
// accessoryView Button
- (void) popOver:(UIButton*)paramSender
{
UITableViewCell *cell = (UITableViewCell*)paramSender.superview;
if (cell != nil)
{
//Table position for popover
UIButton *button = (UIButton *)cell.accessoryView;
if(![self popoverContent])
{
popoverContent = [[self storyboard]instantiateViewControllerWithIdentifier:#"PopoverContent"];
[popoverContent setDelegate:self];
popOverController = [[UIPopoverController alloc]initWithContentViewController:popoverContent];
popOverController.popoverContentSize = CGSizeMake(320.0, 600.0);
[popOverController setDelegate:self];
}
CGRect rect = button.frame;
[popOverController presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
PopoverController.h
#protocol AddDelegate <NSObject>
- (void)backPopover: (int)index;
#end
#property (nonatomic, weak) id <AddDelegate> delegate;
PopoverController.m
#synthesize delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate backPopover:indexPath.row];
}
Please try this.
MyViewController *viewController=[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
UIPopoverController* aPopover = [[UIPopoverController alloc]
initWithContentViewController:popupController];
The problem was that storyboard reference, it actually pointed to a navigation controller. Above code works like a charm.
NavigationController.h
#import <UIKit/UIKit.h>
#protocol NavigationControllerDelegate;
#interface NavigationController : UINavigationController<UINavigationControllerDelegate>
#property (nonatomic , assign)id<NavigationControllerDelegate , UINavigationControllerDelegate> delegate;
-(void)cancelImagePicker:(id)sender;
#end
#protocol NavigationControllerDelegate <NSObject>
- (void)mediaPickerController:(NavigationController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
- (void)mediaPickerControllerDidCancel:(NavigationController *)picker;
#end
NavigationController.m
#import "NavigationController.h"
#import "DataViewController.h"
#interface NavigationController ()
#end
#implementation NavigationController
#synthesize delegate;
-(id)init{
UIViewController *controller = [[DataViewController alloc]initWithNibName:#"DataViewController" bundle:nil];
self = [super initWithRootViewController:controller];
if (self) {
self.navigationBar.topItem.title = #"Data Table";
self.navigationBar.tintColor = [UIColor clearColor];
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel"
style:UIBarButtonSystemItemCancel target:self action:#selector(cancelImagePicker:)];
self.navigationBar.topItem.rightBarButtonItem = rightButton;
}
return self;
}
-(void)cancelImagePicker:(id)sender{
[delegate mediaPickerControllerDidCancel:self];
}
#end
DataViewController.m
.....
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
secondViewController *secondController = [[secondViewController alloc]initWithNibName:#"secondViewController" bundle:nil ];
[self.navigationController pushViewController: secondController animated:YES];
}
.......
I want to add a "cancel" button on secondViewController's navigation bar which performs the action -(void)cancelImagePicker:(id)sender; from NavigationController.m. And the same for pushed third, fourth and fifthViewController. How can this be achieved? Do i have to write code in each viewController or Can i write in common?
I have presented the NavigationController from MainViewController on buttonClick as
- (IBAction)navView:(id)sender {
NavigationController * controller = [[NavigationController alloc]init];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
and implemented the delegation methods there.
You can use notification center instead of delegates, the idea is,
[NSNotificationCenter DefaultCenter] addObserver]
i search for a way to have multiple detail view in iPad application and i find the sample code in apple developer site http://developer.apple.com/library/ios/#samplecode/MultipleDetailViews/Introduction/Intro.html , but now i want to have navigation in detail view which this sample does not cover, i add uinavigationcontroller to detail view as :
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
ReportsViewController_iPad *master = [[ReportsViewController_iPad alloc] initWithNibName:#"ReportsViewController_iPad" bundle:nil];
DetailViewController_iPad *detail = [[DetailViewController_iPad alloc] initWithNibName:#"DetailViewController_iPad" bundle:nil];
UINavigationController *masterNavController = [[[UINavigationController alloc] initWithRootViewController:master ] autorelease];
UINavigationController *detailNavController = [[[UINavigationController alloc] initWithRootViewController:detail ] autorelease];
splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavController , detailNavController, nil];
[window addSubview:splitViewController.view];
[window makeKeyAndVisible];
return YES;
}
but when i run the sample i got error
[UINavigationController showRootPopoverButtonItem:]: unrecognized selector sent to instance...
showRootPopoverButtonItem is a method define in a protocol in RootViewController
#protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
---- ReportsViewController.h
#protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
#protocol DetailViewControllerManagerDelegate
-(void) didSelectRowAtIndexPathPopOver:(NSString *)ID;
#end
#interface ReportsViewController_iPad : ReportsViewController<UISplitViewControllerDelegate , DetailViewControllerManagerDelegate>
{
UISplitViewController *splitViewController;
UIPopoverController *popoverController;
UIBarButtonItem *rootPopoverButtonItem;
}
#property (nonatomic, assign) IBOutlet UISplitViewController *splitViewController;
#property (nonatomic, retain) UIPopoverController *popoverController;
#property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem;
#property(nonatomic, retain) id<DetailViewControllerManagerDelegate> delegate;
-(void)didSelectRowAtIndexPath:(NSString*)ID;
#end
--DetailViewController.h
#import <UIKit/UIKit.h>
#import "ReportsViewController_iPad.h"
#interface DetailViewController_iPad : UIViewController<SubstitutableDetailViewController>
{
UIToolbar *toolbar;
}
#property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
#end
--DetailViewController.m
#import "DetailViewController_iPad.h"
#implementation DetailViewController_iPad
#synthesize toolbar;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark -
#pragma mark Managing the popover
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray insertObject:barButtonItem atIndex:0];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Remove the popover button from the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray removeObject:barButtonItem];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
- (void)dealloc {
[toolbar release];
[super dealloc];
}
#end
So Thanks in advance.
Where definition of method showRootPopoverButtonItem is present, seems like this is not defined. You need to define it.
If you want to avoid crash then you can use -
if ([aViewController respondsToSelector:#selector(showRootPopoverButtonItem:)]) {
[aViewController performSelector:#selector(showRootPopoverButtonItem:) withObject:self.rootPopoverButtonItem];
}
EDIT -
I have checked this and found what you are doing wrong , for e.g. code in willHideViewController-
UIViewController <SubstitutableDetailViewController> *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
this is expecting a view controller, while you are passing navigation controller which in turn has view controller(similar at some other position), so you need to alter these codes as well if you want to pass navigation controller from app delegate.
I need to call a method in the viewcontroller that creates a popupviewcontroller, from the created popupviewcontroller.
For iPad I create it like this:
if (!self.flipsidePopoverController) {
FlipsideViewController *controller = [[[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil] autorelease];
controller.delegate = self;
self.flipsidePopoverController = [[[UIPopoverController alloc] initWithContentViewController:controller] autorelease];
}
if ([self.flipsidePopoverController isPopoverVisible]) {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
}
else
{
/// The important part ///
[self.flipsidePopoverController presentPopoverFromRect:CGRectMake((self.view.frame.size.width-320), 0, (self.view.frame.size.width), 10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Now I wish to call a method in my main view controller from within the popup. How can I achieve that?
My iPhone equivalent is this:
// Creating it //
FlipsideViewController *controller = [[[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil] autorelease];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
Calling a method from within the popup:
if ([self.presentingViewController isKindOfClass:[MainViewController class]])
[(MainViewController*)self.presentingViewController resetClock];
Give the displayed view controller a reference to your main view controller. Eg:
#class MainViewController;
#interface FlipsideViewController : UIViewController
{
}
#property (nonatomic, assign) MainViewController *mainController;
#end
(Don't forget the #synthesize in the implementation!)
Later when you present the popover, just set the property:
[controller setMainController:self];
.h
#import <UIKit/UIKit>
#import AppDelegate.h"
#interface FlipsideViewController : UIViewController
{
}
#property (nonatomic, assign) MainViewController *mainController;
#end
.m
#import "FlipsideViewController.h"
#import "MainViewController.h"
#interface FlipsideViewController ()
#end
#implementation FlipsideViewController
#synthesize mainController = _mainController;
// methods
#end