简体   繁体   English

iOS 如何从 Uiview 呈现 Modal ViewController

[英]iOS how present Modal ViewController from Uiview

i have subclass a UIView and now i need to show a view controller but UIView not have method to present view controller.我有一个UIView的子类,现在我需要显示一个视图 controller 但UIView没有方法来呈现视图 Z59038ABAZ03F2C6E04 this is my problem thank's这是我的问题谢谢

this is a piece of code inside my uiview subclass这是我的 uiview 子类中的一段代码

-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    if ([tabella isEqualToString:@"Articoli"]) {
        NSDictionary *itm=(NSDictionary*)[comanda objectAtIndex:indexPath.row];

        Articoli *aboutViewController = [[Articoli alloc] initWithNibName:@"Articoli" bundle:nil];

        aboutViewController.modalPresentationStyle = UIModalPresentationFormSheet;
        aboutViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
        aboutViewController.idarticolo=[itm objectForKey:@"idarticolo"];
        CGRect aboutSheetFrame = aboutViewController.view.frame;

        UIViewController *viewController = [UIViewController new];
        viewController.view = self;

        //here xcode give me a red error
        [self presentViewController:viewController animated:YES completion:nil] ;

        aboutSheetFrame =CGRectZero;
        aboutViewController.view.superview.bounds = aboutSheetFrame;

    }
}

When you need a communication between UIView instance and UIViewController , there are a few known iOS concepts, which you should adhere to.当您需要在UIView实例和UIViewController之间进行通信时,您应该遵守一些已知的 iOS 概念。 As you have figured out that UIView cannot really present a new controller (missing either presetViewController:animated:completion methods or navigationController property, which are both present in UIViewController ).正如您已经发现UIView不能真正呈现新的 controller (缺少presetViewController:animated:completion方法或navigationController控制器属性,它们都存在于UIViewController中)。

Views are supposed to be the most reusable parts of your code, so you must think of a way to design your views to be completely blind to where they are at.视图应该是代码中最可重用的部分,因此您必须想办法将视图设计为完全看不到它们所在的位置。 They usually only know about user interaction.他们通常只知道用户交互。

So first, what you must do is refactor your view.所以首先,你必须做的是重构你的视图。

  1. If your UIView is supposed to be a UIControl (has some kind of target selectors), you need to use add target in your controller to get callback from view interaction.如果您的UIView应该是UIControl (具有某种目标选择器),则需要在 controller 中使用 add target 从视图交互中获取回调。
  2. You can use delegate pattern as used in UITableView or UICollectionView , which is designed as a protocol.您可以使用设计为协议的UITableViewUICollectionView中使用的委托模式。
  3. You can use gesture recognizers added to a view ( UITapGestureRecognizer for example), so the controller knows about user interaction.您可以使用添加到视图的手势识别器(例如UITapGestureRecognizer ),因此 controller 知道用户交互。

You can even mix and match those architectural patterns.您甚至可以混合和匹配这些架构模式。

But you should really look into iOS programming basics, to understand this better.但是您应该真正了解iOS 编程基础知识,以便更好地理解这一点。

In addition the first error I see in your code is that you create a generic UIViewController , when you should really be creating custom subclasses of it, defined in Storyboard and separate subclass of UIViewController .此外,我在您的代码中看到的第一个错误是您创建了一个通用UIViewController ,当您真正应该创建它的自定义子类时,在 Storyboard 和UIViewController的单独子类中定义。

The second error I see is that your UIView responds do tableView:didSelectRowAtIndexPath: method, which should in fact never happen.我看到的第二个错误是您的UIView响应 do tableView:didSelectRowAtIndexPath:方法,实际上这应该永远不会发生。 All this code must be moved back to one UIViewController subclass.所有这些代码都必须移回一个UIViewController子类。

You can do this without any view hierarchy issues using the below code.您可以使用以下代码在没有任何视图层次结构问题的情况下执行此操作。

ObjectiveC客观C

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

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

Swift Swift

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
     topVC = topVC!.presentedViewController
}
topVC?.presentViewController........

PresentViewController is method of UIViewController class not of UIView , you can do one thing, create UIViewController instance and set its view to the view you have and then present it. PresentViewController is method of UIViewController class not of UIView , you can do one thing, create UIViewController instance and set its view to the view you have and then present it. Something like below像下面的东西

YourCustomView *customView = [[YourCustomView alloc]initWithFrame:someFrame];

UIViewController *viewController = [UIViewController new];
viewController.view = customView;

//From currentViewController present this 
[self presentViewController:viewController animated:YES completion:nil] ;

Customize this code as per your requirement根据您的要求自定义此代码

But as you are in view you need to pass this event to viewController, so better implement delegate method and at place where you calling present viewController call delegate which is implemented in ViewController and in side that presentViewController with customView set to its view property但是当您在视图中时,您需要将此事件传递给 viewController,因此更好地实现委托方法,并在您调用当前 viewController 调用委托的地方,该委托在 ViewController 中实现,并且在将 customView 设置为其视图属性的 presentViewController 中

You can also present your viewcontroller from the navigation controller object您还可以从导航 controller object 中展示您的视图控制器

Create Global Navigation Object in App Delegate or anywhere, you can access navigationcontroller object from view在 App Delegate 或任何地方创建全局导航 Object,您可以从视图中访问导航控制器 object

@property (strong, nonatomic) UINavigationController *gblNavigation;

//Present viewcontroller from NavigationController object //从 NavigationController object 呈现视图控制器

[gblNavigation presentViewController:YOUR_VC_Object animated:YES completion:nil];

You can't present a view controller from a view.您无法从视图中呈现视图 controller。 You can only present a view controller from a view controller.您只能从视图 controller 中呈现视图 controller。

Apple wants views to be dumb.苹果希望观点是愚蠢的。 That is views should only know how to display content.那就是视图应该只知道如何显示内容。 View should not respond to user interaction: that should be passed to a view controller.视图不应响应用户交互:应传递给视图 controller。

You may want to consider using a delegate pattern, target action, or something similar to allow a view controller to control the interaction.您可能需要考虑使用委托模式、目标操作或类似的东西来允许视图 controller 控制交互。

iOS 15, compatible down to iOS 13 iOS 15,兼容低至 iOS 13

Based on Shamsudheen TK solution for anyone who comes across this question in the future.基于 Shamsudheen TK 解决方案,适用于将来遇到此问题的任何人。

let presentedWindow = UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first { $0.isKeyWindow }
guard let currentViewController = presentedWindow?.rootViewController else {
  return
}
currentViewController.present(UIViewController(nibName: nil, bundle: nil), animated: true)

Note that connectedScenes is available only since iOS 13. If you need to support earlier versions of iOS, you have to place this in an if #available(iOS 13, *) statement.请注意,connectedScenes 仅在 iOS 13 之后可用。如果您需要支持 iOS 的早期版本,则必须将其放在 if #available(iOS 13, *) 语句中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM