2017-04-19 66 views
1

我试图在UIAlertController内部放置一个自定义视图。我遇到了一些与定制视图大小有关的奇怪问题。UIAlertController中的自定义视图

我想要自定义视图跨越UIAlertController的宽度,无论可能如何。我正在使用CGRectGetWidth(alertController.view.bounds)来获取警报控制器的宽度。但是,这似乎是要返回整个视图的宽度。使用view.frame并没有什么区别。

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"My Title" message:nil preferredStyle:UIAlertControllerStyleAlert]; 

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(alertController.view.bounds), 50)]; 
view.backgroundColor = [UIColor blueColor]; 

[alertController.view addSubview:view]; 
[self presentViewController:alertController animated:YES completion:nil]; 

这产生了下面的结果。我有同样的问题试图获得UIAlertController的X,Y宽度和高度属性。有谁知道我可以如何将这个视图置于警报控制器的中间而不使用硬编码的数字?

enter image description here

回答

4

你不应该这样做。引用文档:

UIAlertController类旨在按原样使用,不支持子类化。

该类的视图层次结构是私有的,不能修改。

如果您违反苹果公司的明确声明,则所有投注都将关闭,即使您可以在当前操作系统版本上使用它,它也可能会破坏任何未来版本。

+0

我要补充的是使用'UIPresentationController'你可以很容易地复制'UIAlertController'的行为并提供你想要的任何视图/控制器。 – jjatie

+0

@jjatie,你有没有使用'UIPresentationController'来复制/扩展'UIAlertController'行为的示例项目/ tuts?我还没有使用'UIPresentationController'。 –

+0

这是一个起点。 CoolPresentationController将会关闭。 https://developer.apple.com/library/content/samplecode/LookInside/Introduction/Intro.html#//apple_ref/doc/uid/TP40014643还有一个关联的WWDC视频 – jjatie

1

下面是一个替代方案。它不是将子视图添加到UIAlertControl的视图层次结构中,而是将UIWindow改为适当的位置。要跟踪UIAlertControl的视图框架,视图控制器将使用obj-c运行时/ swift扩展(它调用UIViewController超类实现)的自定义.view getter进行扩展。这可以避免真正的视图的私有类依赖性,既不能继承UIAlertControl也不能修改它的视图层次结构。

Example screenshot

Objective-C的

#import <objc/runtime.h> 
#import <objc/message.h> 
@implementation AppDelegate 
+ (UIView*)alertHelperView 
{ 
    static UIView *alertHelperView = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     alertHelperView = [UIView new]; 
     alertHelperView.backgroundColor = [UIColor redColor]; 
     alertHelperView.frame = CGRectZero; 
    }); 
    return alertHelperView; 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
    [self.window addSubview:[AppDelegate alertHelperView]]; 
    return YES; 
} 
@end 
@implementation ViewController 

- (void)viewDidAppear:(BOOL)animated { 
    Class class = [UIAlertController class]; 
    class_addMethod(class, @selector(view), imp_implementationWithBlock(^(__unsafe_unretained UIAlertController* self) { 

     struct objc_super super = { 
      .receiver = self, 
      .super_class = class_getSuperclass(class) 
     }; 

     id (*objc_msgSendSuper_typed)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; 

     UIView* myView = objc_msgSendSuper_typed(&super, @selector(view)); 
     CGRect newFrame = myView.frame; 
     if (!self.isBeingPresented) { 
      [AppDelegate alertHelperView].frame = CGRectZero; 
     } else { 
      [[AppDelegate alertHelperView].superview bringSubviewToFront:[AppDelegate alertHelperView]]; 
      [AppDelegate alertHelperView].frame = CGRectMake(newFrame.origin.x, 
                  newFrame.origin.y, 
                  newFrame.size.width/2, 
                  newFrame.size.height/2); 
     } 
     return myView; 
    }), "@@:"); 

    UIAlertController * alert= [UIAlertController 
            alertControllerWithTitle:@"Info" 
            message:@"You are using UIAlertController" 
            preferredStyle:UIAlertControllerStyleAlert]; 

    UIAlertAction* ok = [UIAlertAction 
         actionWithTitle:@"OK" 
         style:UIAlertActionStyleDefault 
         handler:^(UIAlertAction * action) 
         { 
         }]; 
    UIAlertAction* cancel = [UIAlertAction 
          actionWithTitle:@"Cancel" 
          style:UIAlertActionStyleDefault 
          handler:^(UIAlertAction * action) 
          { 
          }]; 

    [alert addAction:ok]; 
    [alert addAction:cancel]; 

    [self presentViewController:alert animated:YES completion:nil]; 
} 
@end 

雨燕3.1

@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate { 

    var window: UIWindow? 
     static var alertHelperView : UIView! 

     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
      AppDelegate.alertHelperView = UIView() 
      AppDelegate.alertHelperView.backgroundColor = .red 
      self.window?.addSubview(AppDelegate.alertHelperView!) 
      return true 
     } 
    } 

    extension UIAlertController { 
     open override var view: UIView! { 
      get { 
       let newFrame : CGRect = super.view.frame 
       if !self.isBeingPresented { 
        AppDelegate.alertHelperView.frame = CGRect.zero 
       } else { 
        AppDelegate.alertHelperView.superview?.bringSubview(toFront: AppDelegate.alertHelperView) 
        AppDelegate.alertHelperView.frame = CGRect(x:newFrame.origin.x,y:newFrame.origin.y,width:newFrame.size.width/2,height:newFrame.size.height/2) 
       } 
       return super.view 
      } 
      set(newValue) { 
       super.view = newValue 
      } 
     } 
    } 

    class ViewController: UIViewController { 
     override func viewDidAppear(_ animated: Bool) { 
      let alertController = UIAlertController(title: "Default Style", message: "A standard alert.", preferredStyle: .alert) 

      let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { action in 
       // ... 
      } 
      alertController.addAction(cancelAction) 

      let OKAction = UIAlertAction(title: "OK", style: .default) { action in 
       // ... 
      } 
      alertController.addAction(OKAction) 
      self.present(alertController, animated: false) { 
      } 
     } 
    } 
}