使用presentViewController从UIView中呈现视图控制器

23

我正在为我的iOS应用程序创建标题栏,并将其制作在一个UIView内。我唯一遇到的问题是“主页按钮”。当按下主页按钮时,它需要转到主页,即ViewController。

然而,[self presentViewController:vc animated:NO completion:NULL]; 似乎不适用于UIView。

我如何解决这个问题?

- (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];
}

你是否已经为按钮添加了选择器?也就是说,按钮是否知道要执行哪个方法?其次,尝试使用popToRootViewControllerAnimated来避免循环。 - Marc
我遇到的错误信息是 - 没有可见的@interface 'TitleBar'声明了选择器presentViewController:animated:completion。 - Ashish Agarwal
这个 homeButtonPressed: 方法定义在哪里?它是在任何视图控制器或某个视图中吗? - nkongara
1
确保您的 ViewController 是 UIViewController 的子类。 - memmons
这是一个UIViewController子类。 - Ashish Agarwal
5个回答

39

你可以不使用委托模式来完成这个操作。这里是代码:

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........

2
在我的应用程序中,我至少使用了20个委托模式来呈现视图控制器,我真的很厌倦这样做。因此,这个答案对我来说就像沙漠中的绿洲一样。非常感谢你。 - Clément Cardonnel
很高兴听到这个好消息 :) - Shamsudheen TK
这个可行,谢谢。不过我有一个情况。有没有办法用一个视图控制器替换 keyWindow 作为 topVC? - N. Der

17

只有UIViewController可以呈现另一个视图控制器,因此如果您需要从视图中显示视图控制器,则有几种方法,其中之一是:

将您的父视图所在的视图控制器设置为其委托

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

然后,在ParentView内调用该代理的方法

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

然后,在您的VC中实现

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

如果你需要将这段代码保留在UIView中并避免使用委托,你可以尝试使用类似以下的技巧(个人不太喜欢但应该可行)

-(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];
}

我收到了消息“在UIView和UIViewController类型的对象上找不到属性委托”。 - Ashish Agarwal
哦,抱歉,我忘了提到这一点 - 你必须在ParentView.h中像这样创建此属性:@property(nonatomic,weak) id delegate。 - alex
homeButtonPressed是(IBAction)还是buttonPressed是-(void)被调用了?此外,您是否为UIButton设置了目标操作(target-action)? - alex
在其他的视图控制器中,你只需要将它们设置为这个视图的代理,并在每一个控制器中实现方法 -(void)buttonPressed; - alex
在 ParentView 中,当我键入 [self.delegate buttonPressed] 时,它再次给出错误消息,指出没有已知的选择器 'buttonPressed' 的实例方法。 - Ashish Agarwal
显示剩余6条评论

6

这是Shamsudheen回答的更符合习惯用语的Swift 3版本:

extension UIApplication {

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

然后,您只需调用以下内容:
UIApplication.topViewController()?.present(...)

3

使用Swift 4 - 4.2 在Shamsudheen TK的答案基础上添加。

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

使用UINavigationController: 这里还有一个额外的功能 -> 您可以将一个UINavigationController与您的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)

2

你可以尝试下面的代码:

 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]; 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接