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
Related
I have a view controller which is my HomeViewController, and I have a modal segue between them.
This is the HomeViewController:
import "HomePageViewController.h"
#import "CreatePageViewController.h"
#import "StackTableViewController.h"
#import "PopUpView.h"
#interface HomePageViewController ()
#property (nonatomic, strong) IBOutlet UIButton *toggleButton;
#property (nonatomic, strong) CreatePageViewController *modalTest;
#property (nonatomic, strong) PopUpView *popup;
#end
#implementation HomePageViewController
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
-(void)viewDidLoad {
[super viewDidLoad];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:Nil];
_modalTest = [storyboard instantiateViewControllerWithIdentifier:#"ModalTest"];
[_toggleButton addTarget:self action:#selector(go) forControlEvents:UIControlEventTouchUpInside];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(hide) name:#"HideAFPopup" object:nil];
}
-(void)go {
_popup = [PopUpView popupWithView:_modalTest.view];
[_popup show];
}
-(void)hide {
[_popup hide];
}
- (IBAction)pushToNextViewController:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc]init];
[self presentModalViewController:vc animated:YES];
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I want to add a navigation controller to StackTableViewController...its just a table view and I want it to have a navigation controller, how should I do this?
Also, why xcode tells me my modal method presentModalViewController is deprecated?
tnx
Create a new instance of UINavigationController, with your StackTableViewController as its rootViewController. Then present the navigation controller:
- (IBAction)pushToNextViewController:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc]init];
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:navCtrl animated:YES completion:nil];
}
Note that presentModalViewController:animated: is deprecated because it has been replaced by presentViewController:animated:completion:.
I have a Add View where when you tap on Category, the following code is executed
- (void)categoryTapped {
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
[self presentViewController:categoryGroupViewController animated:YES completion:nil];
}
CategoryGroupViewController.h looks like
#interface CategoryGroupViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UINavigationController *navigationController;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
CategoryGroupViewController.m looks like
#import "CategoryGroupViewController.h"
#import "Helper.h"
static NSString *CellIdentifier = #"Cell";
#interface CategoryGroupViewController ()
#property(nonatomic, strong) NSArray *categories;
#end
#implementation CategoryGroupViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// (todo) should come from API
self.categories = #[#"Food & Drink", #"Utilities"];
}
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"categoryGroup View loaded");
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self];
self.navigationController.title = #"Pick Category";
}
...
}
When I run my application, I see the following in log
2014-11-20 21:29:53.589 myapp-ios[30332:70b] categoryGroup View loaded
But on Simulator, I see
Why don't I see NavigationController?
As you are presenting your CategoryGroupViewController it will not show Navigation Bar by default.
You have to set your CategoryGroupViewController as rootViewController for UINavigationController and instead of presenting CategoryGroupViewController present newly created UINavigationController.
- (void)categoryTapped{
CategoryGroupViewController *categoryGroupVC = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController: categoryGroupVC];
[self presentViewController:categoryGroupViewController animated:YES completion:nil];
}
as i mentioned above if u want a navigaioncontroller u can set CategoryGroupViewController as a root view for a navigation controller and present it for example,
- (void)categoryTapped
{
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
//add this
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController: categoryGroupViewController];
//present the navigation controller which contains root view controller categoryGroupViewController
[self presentViewController:navController animated:YES completion:nil];
}
You need to instantiate a rootViewController before View did load
[alink]https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html
UIViewController already as a navigationController property, so this is redundant:
// Remove this property from CategoryGroupViewController
#property (nonatomic, strong) UINavigationController *navigationController;
Structuring the user interface in the way you are attempting is also incorrect, and would result in a circular reference between CategoryGroupViewController and UINavigationController. First you need to modify your -viewDidLoad method like so:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"categoryGroup View loaded");
// UINavigationController will use this automatically.
self.title = #"Pick Category";
}
Then you should change the way you go about preseting the view controller in your original method:
- (void)categoryTapped {
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:categoryGroupViewController];
[self presentViewController:navController animated:YES completion:nil];
}
Finally, the introduction in the UINavigationController documentation has a great explanation of how the class should be used. Taking a few minutes to read it would help you tremendously in the future.
I've followed several guides on passing data between view controllers, but they seem to involve setting the secondViewController's property in any equivalent of a -(void)goToNextView method. I'm trying to figure out how to assign a value to a property in a 2nd view controller from the first while using a tab bar controller created in the app delegate.
Current setup:
AppDelegate.m
#synthesize window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
...
UITabBarController *tbc = [[UITabBarController alloc] init];
FirstViewController *vc1 = [[FirstViewController alloc] init];
SecondViewController *vc2 = [[SecondViewController alloc] init];
[tbc setViewControllers: [NSArray arrayWithObjects: vc1, vc2, nil]];
[[self window] setRootViewController:tbc];
[self.window makeKeyAndVisible];
return YES;
}
...
#end
FirstViewController.h
#import "SecondViewController.h"
#interface FirstViewController : UIViewController
{
SecondViewController *vc2;
IBOutlet UISlider *sizeSlider;
}
#property (nonatomic, retain) SecondViewController *vc2;
#property (strong, nonatomic) UISlider *mySlider;
-(IBAction) mySliderAction:(id)sender;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#implementation FirstViewController
#synthesize vc2, mySlider;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UITabBarItem *tbi = [self tabBarItem];
[tbi setTitle:#"xib"];
}
return self;
}
...
- (IBAction) mySliderAction:(id)sender
{
NSString *str = [[NSString alloc] initWithFormat:#"%3.2f", mySlider.value];
if(self.vc2 == nil)
{
SecondViewController *viewTwo = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
self.vc2 = viewTwo;
}
vc2.sliderValueString = str;
}
...
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "myView.h"
#interface SecondViewController : UIViewController
{
NSString *sliderValueString;
}
#property (copy) NSString *sliderValueString;
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize sliderValueString;
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
UITabBarItem *tbi = [self tabBarItem];
[tbi setTitle:#"View 2"];
}
return self;
}
-(void) loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
myView *view = [[myView alloc] initWithFrame:frame];
printf("Slider Value: %s", [sliderValueString UTF8String]);
[self setView: view];
}
...
#end
myView.h and .m are likely irrelevant to the question, but I've got the .h subclassing UIView, and the .m creating the view with -(id)initWithFrame:(CGRect)frame
I'm guessing that I'm assigning the 2nd VC's property in the wrong place (mySliderAction), given that the printf() in the 2nd VC is blank, so my question is: Where should the property be assigned, or what am I doing wrong that is preventing the 2nd VC from allowing it's sliderValueString to not be (or remain) assigned?
Thanks!
You are fine setting the property in mySliderAction, the trouble is that you are setting it on the wrong object.
In the App Delegate you create a viewController for tabControllers' item 2:
SecondViewController *vc2 = [[SecondViewController alloc] init];
In vc1's mySliderAction you also create an instance of vc2:
SecondViewController *viewTwo = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
This is not the instance that you navigate to via the second tab on the tabController, but it is the one who's sliderValueString property you are setting.
Instead of making a new instance here, you need to refer to the already-existing instance:
SecondViewController *viewTwo = [self.tabBarController.viewControllers objectAtIndex:1]
Then you should be ok.
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 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.