【问题标题】:Custom View in UIAlertControllerUIAlertController 中的自定义视图
【发布时间】:2017-04-19 20:46:05
【问题描述】:

我正在尝试将自定义视图放在 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 宽度和高度属性时遇到了同样的问题。有谁知道如何在不使用硬编码数字的情况下将此视图放置在警报控制器的中间?

【问题讨论】:

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


    【解决方案1】:

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

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

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

    如果您违背 Apple 的明确声明,所有赌注都将失败,即使您可以让它在当前操作系统版本上运行,它也可能与任何未来版本中断。

    【讨论】:

    • 我要补充一点,使用UIPresentationController 您可以轻松复制UIAlertController 的行为并提供您想要的任何视图/控制器。
    • @jjatie,你有没有使用UIPresentationController 复制/扩展UIAlertController 行为的示例项目/tuts?我还没有与UIPresentationController 合作过。
    • 这里是一个起点。 CoolPresentationController 接近了。 developer.apple.com/library/content/samplecode/LookInside/… 还有一个相关的 WWDC 视频
    【解决方案2】:

    这是另一种选择。它不是将子视图添加到UIAlertControl 的视图层次结构中,而是添加到UIWindow 的适当位置。为了跟踪UIAlertControl 的视图框架,视图控制器使用调用UIViewController 超类实现的obj-c 运行时/swift 扩展使用自定义.view getter 进行扩展。这样可以避免真正的视图的私有类依赖,并且既不会继承 UIAlertControl 也不会修改它的视图层次结构。

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

    【讨论】:

      【解决方案3】:

      这是我对这个问题的解决方案:

      protocol AlertPresenter {
        func showAlert()
      }
      
      extension AlertPresenter where Self: UIViewController {
        func showAlert() {
          
          guard let customView = CustomAlertView.instance else { return  }
          
          let alert = UIAlertController(title: "", message: nil, preferredStyle: .alert)
                  
          let alertSize = customView.frame.size
          
          let view = UIView(frame: customView.bounds)
          view.center = CGPoint(x: alertSize.width / 2, y: alertSize.height / 2)
          view.backgroundColor = .clear
          view.addSubview(customView)
          
          alert.view.widthAnchor.constraint(equalToConstant: alertSize.width).isActive = true
          alert.view.heightAnchor.constraint(equalToConstant: alertSize.height).isActive = true
      
          alert.view.addSubview(view)
      
          present(alert, animated: true, completion: nil)
        }
      }
      

      CustomAlertView - 您的自定义视图(在我的例子中是使用 .xib 创建的)

      .instance = CustomAlertView 的实例

      然后得到类似的东西

      【讨论】:

        猜你喜欢
        • 2018-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多