我有一个子类UIView
,现在我需要显示一个视图控制器,但UIView
没有显示视图控制器的方法。这是我的问题感谢
这是我的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;
}
}
当你需要UIView
实例和UIViewController
之间的通信时,有一些已知的iOS概念,你应该坚持。正如你已经发现的那样,UIView
不能真正呈现一个新的控制器(缺少presetViewController:animated:completion
方法或navigationController
属性,它们都存在于UIViewController
中)。
视图应该是代码中最可重用的部分,所以你必须想一种方法来设计你的视图,使其完全无视它们的位置。它们通常只知道用户交互。
因此,首先,您必须重构视图
- 如果您的
UIView
应该是UIControl
(具有某种目标选择器),则需要在控制器中使用add-target从视图交互中获取回调 - 您可以使用
UITableView
或UICollectionView
中使用的委托模式,后者被设计为一个协议 - 您可以使用添加到视图中的手势识别器(例如
UITapGestureRecognizer
),以便控制器了解用户交互
您甚至可以混合和匹配这些体系结构模式。
但您应该深入了解iOS编程的基本知识,以便更好地理解这一点。
此外,我在代码中看到的第一个错误是创建了一个通用UIViewController
,而实际上应该创建它的自定义子类,在Storyboard和UIViewController
的单独子类中定义。
我看到的第二个错误是,您的UIView
响应tableView:didSelectRowAtIndexPath:
方法,实际上这应该永远不会发生。所有这些代码都必须移回一个UIViewController
子类。
您可以使用以下代码在没有任何视图层次结构问题的情况下完成此操作。
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........
PresentViewController
是UIViewController
类的方法,而不是UIView
的方法,您可以做一件事,创建UIViewController
实例并将其视图设置为您拥有的视图,然后呈现它。低于
YourCustomView *customView = [[YourCustomView alloc]initWithFrame:someFrame];
UIViewController *viewController = [UIViewController new];
viewController.view = customView;
//From currentViewController present this
[self presentViewController:viewController animated:YES completion:nil] ;
根据您的要求自定义此代码
但当您在视图中时,您需要将此事件传递给viewController,因此更好地实现委托方法,并在您调用当前viewController的地方调用在viewController中实现的委托,以及在customView设置为其视图属性的presentViewController一侧
您还可以从导航控制器对象中展示您的视图控制器
在App Delegate或任何地方创建全局导航对象,您可以从视图访问导航控制器对象
@property (strong, nonatomic) UINavigationController *gblNavigation;
//显示NavigationController对象中的视图控制器
[gblNavigation presentViewController:YOUR_VC_Object animated:YES completion:nil];
您不能从视图中呈现视图控制器。只能从视图控制器中呈现视图控制器。
苹果希望观点是愚蠢的。也就是说,视图应该只知道如何显示内容。视图不应响应用户交互:应将其传递给视图控制器。
您可能需要考虑使用委托模式、目标操作或类似的方法来允许视图控制器控制交互。
iOS 15,兼容iOS 13
基于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)
注意connectedScenes仅在iOS 13之后可用。如果你需要支持早期版本的iOS,你必须将其放在If#available(iOS 13,*)声明中。