23

I am creating a title bar for my iOS application and I am making this inside a UIView. The only issue I am having is with the "home button". When the home button is pressed, it needs to go to the home page, which is ViewController.

However, it doesn't look as if [self presentViewController:vc animated:NO completion:NULL]; works for UIView.

How do I work around this problem ?

- (void) createTitlebar {

    CGRect titleBarFrame = CGRectMake(0, 0, 320, 55);

    //Create the home button on the top right of the page. When clicked, it will navigate to the home page of the application
    homeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    homeButton.frame = CGRectMake(275, 10, 40, 40);
    [homeButton setTag:1];
    [homeButton setImage:[UIImage imageNamed:@"homeIcon.png"] forState:UIControlStateNormal];
    [homeButton addTarget:self action:@selector(homeButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:homeButton];
}

- (IBAction)homeButtonPressed:(id)sender{

    //Transition to the submit button page
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    [vc setModalPresentationStyle:UIModalPresentationFullScreen];
    [self presentViewController:vc animated:NO completion:NULL];
}
Vvk
  • 4,031
  • 29
  • 51
Ashish Agarwal
  • 14,555
  • 31
  • 86
  • 125

5 Answers5

39

You can do this without using the delegate pattern. Here you go

ObjectiveC

UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController......... 

- (UIViewController *)currentTopViewController {
    UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    while (topVC.presentedViewController) {
        topVC = topVC.presentedViewController;
    }
    return topVC;
}

Swift

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil) {
     topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
Shamsudheen TK
  • 30,739
  • 9
  • 69
  • 102
17

Only UIViewController can present another view controller, so if you need to show a viewcontroller from view there are several way, one of them is like this:

make a viewcontroller on which your parent view is situated a delegate of it

ParentView *view = [ParentView new];
...
view.delegate = self;

then, inside ParentView call method of that delegate

- (IBAction)homeButtonPressed:(id)sender {
    [self.delegate buttonPressed];
}

and then, inside your VC implement

 -(void)buttonPressed {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    [vc setModalPresentationStyle:UIModalPresentationFullScreen];
    [self presentViewController:vc animated:NO completion:NULL];
}

If you need to keep this code inside UIView and avoid delegation you can do a trick like this (personally i don't like it but it should work)

-(void)buttonPressed{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    ViewController *vc = [storyboard      instantiateViewControllerWithIdentifier:@"ViewController"];
    [vc setModalPresentationStyle:UIModalPresentationFullScreen];
    [(UIViewController*)self.nextResonder presentViewController:vc animated:NO completion:NULL];
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
alex
  • 2,121
  • 1
  • 18
  • 24
  • I get the message Property delegate not found on object of type .. for both the UIView and the UIViewController – Ashish Agarwal Mar 25 '13 at 20:15
  • Oh,sorry, I forgot to mention this - U have to make this property in ParentView.h like this: @property(nonatomic,weak) id delegate – alex Mar 25 '13 at 20:18
  • is (IBAction)homeButtonPressed or -(void)buttonPressed called? Also did u set the target-action for UIButton? – alex Mar 25 '13 at 20:45
  • Am I writing the code to do delegation inside the UIView or the UIViewController ? – Ashish Agarwal Mar 25 '13 at 20:53
  • inside UIViewController you set it as a delegate of a UIView. Also a couldnt find smth like this in your code [homeButton addTarget:self action:@selector(homeButtonPressed:)];? Are u sure that a button knows what method to call? – alex Mar 25 '13 at 20:54
  • Hmm, but the above code is a part of the UIView class. The idea is that I create a title bar in a UIView class and re-use it in other ViewController classes. If I have to make the ViewController a delegate of UIView, that defeats the purpose of MVC – Ashish Agarwal Mar 25 '13 at 21:04
  • In other viewcontrollers you just will set up them as delegates of this view and in each of them you will implement method -(void)buttonPressed; – alex Mar 25 '13 at 21:07
  • Only - (IBAction)homeButtonPressed:(id)sender{ [self.delegate buttonPressed];} is implemented inside UIView – alex Mar 25 '13 at 21:08
  • In the ParentView, when I type `[self.delegate buttonPressed]`, it once again gives me the error message saying No known instance method for selector 'buttonPressed' – Ashish Agarwal Mar 25 '13 at 21:23
  • declare buttonPressed method in VC.h file or replace the code for:[self.delegate performSelector:@selector(buttonPressed:) withObject:nil]; – alex Mar 26 '13 at 03:26
  • just figured it out. I was missing `view.delegate = self;` – Ashish Agarwal Mar 26 '13 at 04:24
6

Here's a more idiomatic Swift 3 version of Shamsudheen's answer:

extension UIApplication {

    static func topViewController() -> UIViewController? {
        guard var top = shared.keyWindow?.rootViewController else {
            return nil
        }
        while let next = top.presentedViewController {
            top = next
        }
        return top
    } 
}

Then you can just call:

UIApplication.topViewController()?.present(...)
Hans Brende
  • 7,847
  • 4
  • 37
  • 44
3

With Swift 4 - 4.2 Adding onto Shamsudheen TK's answer.

var topVC = UIApplication.shared.keyWindow?.rootViewController
    while((topVC!.presentedViewController) != nil) {
        topVC = topVC!.presentedViewController
    }
    let customViewController = CustomViewController()
    topVC?.present(customViewController, animated: true, completion: nil)

With UINavigationController: Here is also an additional feature -> You can pass along a UINavigationController with your customViewController.

 var topVC = UIApplication.shared.keyWindow?.rootViewController
    while((topVC!.presentedViewController) != nil) {
        topVC = topVC!.presentedViewController
    }
    let customViewController = CustomViewController()
    let navController = UINavigationController(rootViewController: CustomViewController)
    topVC?.present(navController, animated: true, completion: nil)
N. Der
  • 507
  • 4
  • 18
2

You can try below code

 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
 ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
 UIViewController *vc1 = [UIApplication sharedApplication].keyWindow.rootViewController;
 [vc1 presentViewController:vc animated:YES completion:nil]; 
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81