UIAlertController中的自定义视图

时间:2017-04-19 20:46:06

标签: ios custom-controls subview uialertcontroller custom-view

我正在尝试将自定义视图放在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

2 个答案:

答案 0 :(得分:5)

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

  

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

     

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

如果你反对像Apple这样明确的声明,所有的赌注都已关闭,即使你可以让它在当前的操作系统版本上工作,它也可能会破坏任何未来的版本。

答案 1 :(得分:1)

这是一个替代方案。它不会将子视图添加到UIAlertControl的视图层次结构中,而是添加到UIWindow的适当位置。为了跟踪UIAlertControl的视图帧,视图控制器使用obj-c runtime / swift扩展来扩展自定义.view getter,该扩展调用UIViewController超类实现。这允许避免真正的视图的私有类依赖,既不是子类UIAlertControl或修改它的视图层次结构。

Example screenshot

<强>目标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

Swift 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) {
            }
        }
    }
}