2016-05-26 22 views
5

Ich versuche, eine Lösch-Popup-Ansicht zu bestätigen. Da das Design, das ich möchte, ist sehr unterschiedlich von der Art der typischen UIAlertView Popup, entschied ich mich, eine benutzerdefinierte ConfirmationViewController, die ich auslösen würde, Popup erstellen. HierSwift Custom UIAlertView

ist, was die typische UIAlertView wie folgt aussieht:

enter image description here

Und hier ist, was ich will mein aussehen:

enter image description here

hier, wie ich zur Zeit mache meine Gewohnheit ConfirmationViewController popup:

let confirmationViewController = ConfirmationViewController() 
confirmationViewController.delegate = self 
confirmationViewController.setTitleLabel("Are you sure you want to remove \(firstName)?") 
confirmationViewController.modalPresentationStyle = UIModalPresentationStyle.Popover 
confirmationViewController.preferredContentSize = CGSizeMake(230, 130) 

let popoverConfirmationViewController = confirmationViewController.popoverPresentationController 
popoverConfirmationViewController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0) 
popoverConfirmationViewController?.delegate = self 
popoverConfirmationViewController?.sourceView = self.view 
popoverConfirmationViewController?.sourceRect = CGRectMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds),0,0) 
presentViewController(
    confirmationViewController, 
    animated: true, 
    completion: nil) 

Und hier ist, wie ich bin immer die Benachrichtigung, wenn die CANCEL oder REMOVE Taste gedrückt wird:

extension UserProfileTableViewController: ConfirmationViewControllerDelegate { 
    func cancelButtonPressed() { 
     print("Cancel button pressed") 
    } 

    func confirmationButtonPressed(objectToDelete: AnyObject?) { 
     print("Delete button pressed") 
    } 
} 

Aber was Ich mag über ein UIAlertView ist, dass ich in der Aktion codieren kann ich durchgeführt werden soll, wenn ein bestimmte Taste gedrückt wird, wie folgt aus:

let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .Alert) 

let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: {(ACTION) in 
    print("Perform cancel action") 
}) 

let deleteAction = UIAlertAction(title: "Remove", style: .Destructive, handler: {(ACTION) in 
    print("Perform delete action") 
}) 

alertController.addAction(cancelAction) 
alertController.addAction(deleteAction) 

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

Also meine Frage ist, wie kann ich eine Abschluss-Handler (Inline) derart, dass, wenn die CANCEL oder REMOVE Taste mit meiner benutzerdefinierten gedrückt ConfirmationViewController Ich kann die Aktion auslösen, genauso wie ich gezeigt habe, wie es mit der UIAlertController gemacht wird, anstatt wie ich es gerade mit Delegierung mache?

Ist die Antwort, um nur das benutzerdefinierte Popup zu erstellen, das ich mit einer UIAlertController suche? Und wenn ja, wie kann ich es so anpassen, wie ich es mir wünsche?

Vielen Dank im Voraus und sorry für den langen Post :)

P. S. Hier ist, was meine ConfirmationViewController und ConfirmationViewControllerDelegate wie folgt aussehen:

protocol ConfirmationViewControllerDelegate { 
    func cancelButtonPressed() 
    func confirmationButtonPressed(objectToDelete: AnyObject?) 
} 

class ConfirmationViewController: UIViewController { 
    var didSetupConstraints = false 

    let titleLabel = UILabel.newAutoLayoutView() 
    let buttonContainer = UIView.newAutoLayoutView() 
    let cancelButton = ButtonWithPressingEffect.newAutoLayoutView() 
    let confirmationButton = ButtonWithPressingEffect.newAutoLayoutView() 

    var delegate: ConfirmationViewControllerDelegate? 

    var objectToDelete: AnyObject? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     view.backgroundColor = UIColor.whiteColor() 

     titleLabel.numberOfLines = 0 

     cancelButton.backgroundColor = UIColor.colorFromCode(0x7f7f7f) 
     cancelButton.layer.cornerRadius = 5 
     cancelButton.setAttributedTitle(NSMutableAttributedString(
      string: "CANCEL", 
      attributes: [ 
       NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Demi", size: 12)!, 
       NSForegroundColorAttributeName: UIColor.whiteColor(), 
       NSKernAttributeName: 0.2 
      ] 
     ), forState: UIControlState.Normal) 
     cancelButton.addTarget(self, action: #selector(cancelButtonPressed), forControlEvents: .TouchUpInside) 

     confirmationButton.backgroundColor = Application.redColor 
     confirmationButton.layer.cornerRadius = 5 
     confirmationButton.setAttributedTitle(NSMutableAttributedString(
      string: "REMOVE", 
      attributes: [ 
       NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Demi", size: 12)!, 
       NSForegroundColorAttributeName: UIColor.whiteColor(), 
       NSKernAttributeName: 0.2 
      ] 
     ), forState: UIControlState.Normal) 
     confirmationButton.addTarget(self, action: #selector(confirmationButtonPresssed), forControlEvents: .TouchUpInside) 

     view.addSubview(titleLabel) 
     view.addSubview(buttonContainer) 
     buttonContainer.addSubview(cancelButton) 
     buttonContainer.addSubview(confirmationButton) 
     updateViewConstraints() 
    } 

    func cancelButtonPressed() { 
     delegate?.cancelButtonPressed() 
     dismissViewControllerAnimated(false, completion: nil) 
    } 

    func confirmationButtonPresssed() { 
     delegate?.confirmationButtonPressed(objectToDelete) 
     dismissViewControllerAnimated(false, completion: nil) 
    } 

    func setTitleLabel(text: String) { 
     let paragraphStyle = NSMutableParagraphStyle() 
     paragraphStyle.alignment = NSTextAlignment.Center 
     paragraphStyle.lineSpacing = 4.5 
     titleLabel.attributedText = NSMutableAttributedString(
      string: text, 
      attributes: [ 
       NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Regular", size: 14)!, 
       NSForegroundColorAttributeName: UIColor.colorFromCode(0x151515), 
       NSKernAttributeName: 0.5, 
       NSParagraphStyleAttributeName: paragraphStyle 
      ] 
     ) 
    } 

    override func updateViewConstraints() { 
     if !didSetupConstraints { 
      titleLabel.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10), excludingEdge: .Bottom) 
      titleLabel.autoAlignAxisToSuperviewAxis(.Vertical) 

      buttonContainer.autoPinEdge(.Top, toEdge: .Bottom, ofView: titleLabel, withOffset: 3) 
      buttonContainer.autoAlignAxisToSuperviewAxis(.Vertical) 
      buttonContainer.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 10) 

      let contactViews: NSArray = [cancelButton, confirmationButton] 
      contactViews.autoDistributeViewsAlongAxis(.Horizontal, alignedTo: .Horizontal, withFixedSpacing: 7, insetSpacing: true, matchedSizes: false) 

      cancelButton.autoPinEdgeToSuperviewEdge(.Top) 
      cancelButton.autoPinEdgeToSuperviewEdge(.Bottom) 
      cancelButton.autoSetDimensionsToSize(CGSize(width: 100, height: 50)) 

      confirmationButton.autoPinEdgeToSuperviewEdge(.Top) 
      confirmationButton.autoPinEdgeToSuperviewEdge(.Bottom) 
      confirmationButton.autoSetDimensionsToSize(CGSize(width: 100, height: 50)) 

      didSetupConstraints = true 
     } 

     super.updateViewConstraints() 
    } 
} 
+0

Ist die ConfirmationViewController Klasse unter Ihrer Kontrolle und möglich zu bearbeiten? – SeanCAtkinson

+0

Yessir, ich habe gerade meinen Code für den ConfirmationViewController @SeanCAtkinson aktualisiert – Thomas

Antwort

5

etwas wie das folgende sollte es zulassen. Beachten Sie, dass einige Verbesserungen möglich sind. Zum Beispiel könnten Sie ein Generic für das Objekt verwenden, das anstelle von AnyObject gelöscht wird. Sie müssen es auch nicht unbedingt weitergeben, wenn Sie das Closure trotzdem inline übergeben, so dass Sie es wahrscheinlich einfach entfernen könnten.

Sie können auch Ihre Tasten mehr wiederverwendbar, anstatt feste Codierung machen abzubrechen und zu entfernen, aber jetzt sind wir Thema aussteigen :)

class ConfirmViewController : UIViewController { 
    var onCancel : (() -> Void)? 
    var onConfirm : ((AnyObject?) -> Void)? 

    var objectToDelete : AnyObject? 

    func cancelButtonPressed() { 
     // defered to ensure it is performed no matter what code path is taken 
     defer { 
      dismissViewControllerAnimated(false, completion: nil) 
     } 

     let onCancel = self.onCancel 
     // deliberately set to nil just in case there is a self reference 
     self.onCancel = nil 
     guard let block = onCancel else { return } 
     block() 
    } 

    func confirmationButtonPresssed() { 
     // defered to ensure it is performed no matter what code path is taken 
     defer { 
      dismissViewControllerAnimated(false, completion: nil) 
     } 
     let onConfirm = self.onConfirm 
     // deliberately set to nil just in case there is a self reference 
     self.onConfirm = nil 
     guard let block = onConfirm else { return } 
     block(self.objectToDelete) 
    } 
} 

let confirm = ConfirmViewController() 
confirm.objectToDelete = NSObject() 
confirm.onCancel = { 
    // perform some action here 
} 
confirm.onConfirm = { objectToDelete in 
    // delete your object here 
} 
+0

Das funktioniert super! Vielen Dank Mann :) – Thomas

+0

Ich mag dieses Design-Muster sehr. Gibt es einen bestimmten Grund, warum Delegationen über diese Art von Mustern für Ansichten verwendet werden? @SeanCAtkinson – Thomas

+1

Hängt wirklich vom Anwendungsfall ab. In diesem Fall funktioniert eine blockbasierte API gut, weil sie einfach ist und Sie das Verhalten beim Erstellen der Instanz deklarieren können. Wenn Ihre Anforderungen komplexer werden, werden Sie stattdessen zu einem Delegierten neigen. – SeanCAtkinson