2015-09-25 1 views
28

Я пытаюсь сделать таблицу действий, как она отображается в приложении сообщений на iOS, когда мы пытаемся прикрепить изображение, как на скриншоте.UIAlertController - добавить пользовательские представления в таблицу действий

Я понял в новом UIAlertController, мы не можем соответствовать никаким пользовательским представлениям. Как я могу это сделать?

Мой код выглядит довольно стандартным.

let alertController = UIAlertController(title: "My AlertController", message: "tryna show some images here man", preferredStyle: UIAlertControllerStyle.ActionSheet) 

     let okAction = UIAlertAction(title: "oks", style: .Default) { (action: UIAlertAction) -> Void in 
     alertController.dismissViewControllerAnimated(true, completion: nil) 
    } 
    let cancelAction = UIAlertAction(title: "Screw it!", style: .Cancel) { (action: UIAlertAction) -> Void in 
     alertController.dismissViewControllerAnimated(true, completion: nil) 
    } 

    alertController.addAction(okAction) 
    alertController.addAction(cancelAction) 

    self.presentViewController(alertController, animated: true, completion: nil) 

enter image description here

ответ

68

UIAlertController расширяет UIViewController, который имеет свойство вида. Вы можете добавить subviews к этому представлению к желанию вашего сердца. Единственная проблема - правильно настроить контроллер предупреждения. Вы могли бы сделать что-то подобное, но это может легко сломаться в следующий раз, когда Apple отрегулирует дизайн UIAlertController.

Свифта 3

let alertController = UIAlertController(title: "\n\n\n\n\n\n", message: nil, preferredStyle: UIAlertControllerStyle.actionSheet) 

    let margin:CGFloat = 10.0 
    let rect = CGRect(x: margin, y: margin, width: alertController.view.bounds.size.width - margin * 4.0, height: 120) 
    let customView = UIView(frame: rect) 

    customView.backgroundColor = .green 
    alertController.view.addSubview(customView) 

    let somethingAction = UIAlertAction(title: "Something", style: .default, handler: {(alert: UIAlertAction!) in print("something")}) 

    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert: UIAlertAction!) in print("cancel")}) 

    alertController.addAction(somethingAction) 
    alertController.addAction(cancelAction) 

    DispatchQueue.main.async { 
     self.present(alertController, animated: true, completion:{}) 
    } 

Свифта

let alertController = UIAlertController(title: "\n\n\n\n\n\n", message: nil, preferredStyle: UIAlertControllerStyle.actionSheet) 

let margin:CGFloat = 10.0 
let rect = CGRect(x: margin, y: margin, width: alertController.view.bounds.size.width - margin * 4.0, height: 120) 
let customView = UIView(frame: rect) 

customView.backgroundColor = .green 
alertController.view.addSubview(customView) 

let somethingAction = UIAlertAction(title: "Something", style: .default, handler: {(alert: UIAlertAction!) in print("something")}) 

let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert: UIAlertAction!) in print("cancel")}) 

alertController.addAction(somethingAction) 
alertController.addAction(cancelAction) 

self.present(alertController, animated: true, completion:{}) 

Objective-C

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"\n\n\n\n\n\n" message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 

    CGFloat margin = 8.0F; 
    UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(margin, margin, alertController.view.bounds.size.width - margin * 4.0F, 100.0F)]; 
    customView.backgroundColor = [UIColor greenColor]; 
    [alertController.view addSubview:customView]; 

    UIAlertAction *somethingAction = [UIAlertAction actionWithTitle:@"Something" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}]; 
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {}]; 
    [alertController addAction:somethingAction]; 
    [alertController addAction:cancelAction]; 
    [self presentViewController:alertController animated:YES completion:^{}]; 

Это, как говорится, гораздо меньше, взломанный подход заключается в том, чтобы сделать свой собственный подкласский вид, который работает аналогично макету UIAlertActionStyle UIAlertController. На самом деле, тот же код выглядит немного отличается прошивкой 8 и прошивкой 9.

IOS 8 enter image description here

IOS 9 enter image description here

IOS 10 enter image description here

+0

Вот удивительный и очень полезный, я все еще получаю строку за зеленым видом на полях. Наверное, я поставлю контейнерный вид вокруг зеленого представления. с 0 полями. – CalZone

+0

Спасибо, приятель. Это было фантастично. Просто слегка подгонял ширину к пользовательскому виду, но все хорошо! Приветствия. – Felipe

+0

Привет всем Может ли кто-нибудь дать мне образец проекта для 1-го скриншота ??? –

4

Для ленивых людей оптимизированные версии Swift 3.0 и iOS> = 9 п @ ответ Келлера:

let alertController = UIAlertController(title: "\n\n\n\n\n\n", message: nil, preferredStyle: UIAlertControllerStyle.actionSheet) 

let margin:CGFloat = 10.0 
let rect = CGRect(x: margin, y: margin, width: alertController.view.bounds.size.width - margin * 4.0, height: 120) 
let customView = UIView(frame: rect) 

customView.backgroundColor = .green 
alertController.view.addSubview(customView) 

let somethingAction = UIAlertAction(title: "Something", style: .default, handler: {(alert: UIAlertAction!) in print("something")}) 

let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert: UIAlertAction!) in print("cancel")}) 

alertController.addAction(somethingAction) 
alertController.addAction(cancelAction) 

self.present(alertController, animated: true, completion:{}) 
3

я написал расширение для UIAlertController (в Swift 4), который решает проблемы компоновки с autolayout. В случае, если что-то не работает (из-за будущих изменений в макете UIAlertController) существует даже резервная строка сообщения.

import Foundation 

extension UIAlertController { 

    /// Creates a `UIAlertController` with a custom `UIView` instead the message text. 
    /// - Note: In case anything goes wrong during replacing the message string with the custom view, a fallback message will 
    /// be used as normal message string. 
    /// 
    /// - Parameters: 
    /// - title: The title text of the alert controller 
    /// - customView: A `UIView` which will be displayed in place of the message string. 
    /// - fallbackMessage: An optional fallback message string, which will be displayed in case something went wrong with inserting the custom view. 
    /// - preferredStyle: The preferred style of the `UIAlertController`. 
    convenience init(title: String?, customView: UIView, fallbackMessage: String?, preferredStyle: UIAlertControllerStyle) { 

     let marker = "__CUSTOM_CONTENT_MARKER__" 
     self.init(title: title, message: marker, preferredStyle: preferredStyle) 

     // Try to find the message label in the alert controller's view hierarchie 
     if let customContentPlaceholder = self.view.findLabel(withText: marker), 
      let customContainer = customContentPlaceholder.superview { 

      // The message label was found. Add the custom view over it and fix the autolayout... 
      customContainer.addSubview(customView) 

      customView.translatesAutoresizingMaskIntoConstraints = false 
      customContainer.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[customView]-|", options: [], metrics: nil, views: ["customView": customView])) 
      customContainer.addConstraint(NSLayoutConstraint(item: customContentPlaceholder, 
                  attribute: .top, 
                  relatedBy: .equal, 
                  toItem: customView, 
                  attribute: .top, 
                  multiplier: 1, 
                  constant: 0)) 
      customContainer.addConstraint(NSLayoutConstraint(item: customContentPlaceholder, 
                  attribute: .height, 
                  relatedBy: .equal, 
                  toItem: customView, 
                  attribute: .height, 
                  multiplier: 1, 
                  constant: 0)) 
      customContentPlaceholder.text = "" 
     } else { // In case something fishy is going on, fall back to the standard behaviour and display a fallback message string 
      self.message = fallbackMessage 
     } 
    } 
} 

private extension UIView { 

    /// Searches a `UILabel` with the given text in the view's subviews hierarchy. 
    /// 
    /// - Parameter text: The label text to search 
    /// - Returns: A `UILabel` in the view's subview hierarchy, containing the searched text or `nil` if no `UILabel` was found. 
    func findLabel(withText text: String) -> UILabel? { 
     if let label = self as? UILabel, label.text == text { 
      return label 
     } 

     for subview in self.subviews { 
      if let found = subview.findLabel(withText: text) { 
       return found 
      } 
     } 

     return nil 
    } 
} 

А вот пример использования:

// Create a custom view for testing... 
let customView = UIView() 
customView.translatesAutoresizingMaskIntoConstraints = false 
customView.backgroundColor = .red 

// Set the custom view to a fixed height. In a real world application, you could use autolayouted content for height constraints 
customView.addConstraint(NSLayoutConstraint(item: customView, 
              attribute: .height, 
              relatedBy: .equal, 
              toItem: nil, 
              attribute: .notAnAttribute, 
              multiplier: 1, 
              constant: 100)) 

// Create the alert and show it 
let alert = UIAlertController(title: "Alert Title", 
           customView: customView, 
           fallbackMessage: "This should be a red rectangle", 
           preferredStyle: .actionSheet) 

alert.addAction(UIAlertAction(title: "Yay!", style: .default, handler: nil)) 
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) 

self.present(alert, animated: true, completion: nil) 

Который покажет что-то вроде этого: enter image description here

+0

Это хорошо работает. Просто интересно, если это будет отвергнуто в процессе обзора, любая идея? – Knolraap

+2

Не существует частного API, поэтому я не знаю, почему Apple должна его отклонить. – Zaggo