12

Genellikle projede kullanılabilecek ve bir sol menü düğmesi gibi birçok kez bir yan menüyü açmak için projede kullanılabilecek önceden tanımlanmış bir UIBarButtonItem kümesi var. Farklı UIViewController s'de sunulan görünüm denetleyicisini kapatan bir kapatma düğmesi de kullanılabilir.Projenin herhangi bir UIViewController'ına bar düğme öğeleri ekleme Genel Genel zarif yolu

Klasik yol, bu düğmeleri gerektiği gibi eklemektir, ancak bu bir kod çoğaltması sunar ve hepimiz bundan kaçınmak isteriz. Daha sonra kullanım

enum BarButtonItemType { 
    case menu, close, notification 
} 

enum BarButtonItemPosition{ 
    case right, left 
} 

extension UIViewController { 

    func add(barButtons:[BarButtonItemType], position: BarButtonItemPosition) { 

     let barButtonItems = barButtons.map { rightBarButtonType -> UIBarButtonItem in 
      switch rightBarButtonType { 
      case .menu: 
       return UIBarButtonItem(image: UIImage(named:"menu"), 
        style: .plain, 
        target: self, 
        action: #selector(presentLeftMenu(_:))) 
      case .notification: 
       return UIBarButtonItem(image: UIImage(named:"notification"), 
       style: .plain, 
       target: self, 
       action: #selector(showNotification(_:))) 
      case .close: 
       return UIBarButtonItem(image: UIImage(named:"close"), 
        style: .plain, 
        target: self, 
        action: #selector(dismissController(_:))) 
      } 
     } 

     switch position { 
     case .right: 
      self.navigationItem.rightBarButtonItems = barButtonItems 
     case .left: 
      self.navigationItem.leftBarButtonItems = barButtonItems 
     } 
    } 

    // MARK: Actions 
    @objc fileprivate func presentLeftMenu(_ sender:AnyObject) { 
     self.parent?.presentLeftMenuViewController(sender) 
    } 

    @objc fileprivate func dismissController(_ sender:AnyObject) { 
     self.dismiss(animated: true, completion: nil) 
    } 

    @objc fileprivate func showNotification(_ sender:AnyObject) { 
     let notificationViewController = UINavigationController(rootViewController:NotificationViewController()) 
     self.present(notificationViewController, animated: true, completion: nil) 
    } 
} 

ve: my yaklaşımın

override func viewDidLoad() { 
    super.viewDidLoad() 
    self.add(barButtons: [.close], position: .right) 
    self.add(barButtons: [.menu], position: .left) 
} 

sınırlamalar şunlardır:

  • bir yaklaşım ile gelip listem ama kusursuz olmaktan uzak

    Uzantının, yeni görünüm denetleyicisini nasıl örnekleyeceğini (örneğin bildirim durumu) ve ne gerekiyorsa gerektiğini bilmesi gerekir. Kontrolör

  • Size sadece UIViewController

  • zarif değil sunmak istediğiniz varsayar parametrelerle inited edilmelidir.

Ben, daha fazla esneklik ile herhangi bir düşünce amaçlanan sonuca ulaşabileceği programlama odaklı Swift dil ve protokolle daha iyi bir yol olduğunu eminim?

cevap

1

Varsayılan bir bar düğmesi yapılandırmasına sahip olduğunuzdan ancak belirli bir şekilde (UIViewController alt sınıfına) bar düğmesi eylem uygulamalarına sahip olduğunuz anlaşılıyor. 1. "Uzantının yeni görünüm denetleyicisini nasıl oluşturacağını bilmesi gerekiyor" ve ikinci noktanız 2. "UIViewController'ı sunmak istediğinizi varsayarız", bu uzantının bu işi bir alt sınıfa vermesi için iyi bir işarettir. Bu eylemler ile ne yapacağını bilir. Burada örnek bir uygulama yaptım:

enum BarButtonItemPosition { 
    case right, left 
} 

enum BarButtonItemType { 
    case menu(BarButtonItemPosition) 
    case close(BarButtonItemPosition) 
    case notification(BarButtonItemPosition) 
} 

/// Has default implementation on UIViewControllers that conform to BarButtonActions. 
protocol BarButtonItemConfiguration: class { 

    func addBarButtonItem(ofType type: BarButtonItemType) 
} 

/// Hate that we're forced to expose button targets to objc runtime :(
/// but I don't know any other way for the time being, maybe in Swift 6 :) 
@objc protocol BarButtonActions { 
    @objc func presentLeftMenu(_ sender:AnyObject) 
    @objc func dismissController(_ sender:AnyObject) 
    @objc func showNotification(_ sender:AnyObject) 
} 

extension BarButtonItemConfiguration where Self: UIViewController, Self: BarButtonActions { 

    func addBarButtonItem(ofType type: BarButtonItemType) { 

     func newButton(imageName: String, position: BarButtonItemPosition, action: Selector?) { 
      let button = UIBarButtonItem(image: UIImage(named: imageName), style: .plain, target: self, action: action) 
      switch position { 
      case .left: self.navigationItem.leftBarButtonItem = button 
      case .right: self.navigationItem.rightBarButtonItem = button 
      } 
     } 

     switch type { 
     case .menu(let p): newButton(imageName: "", position: p, action: #selector(Self.presentLeftMenu(_:))) 
     case .notification(let p): newButton(imageName: "", position: p, action: #selector(Self.showNotification(_:))) 
     case .close(let p): newButton(imageName: "", position: p, action: #selector(Self.dismissController(_:))) 
     } 
    } 
} 

/// Conform to this in subclasses of UIViewController and implement BarButtonActions (its impl. differs from vc to vc). 
protocol BarButtonConfigarable: BarButtonItemConfiguration, BarButtonActions {} 

/// example 
class SampleVC: UIViewController, BarButtonConfigarable { 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     addBarButtonItem(ofType: .menu(.right)) 
     addBarButtonItem(ofType: .menu(.left)) 
    } 

    @objc func presentLeftMenu(_ sender:AnyObject) { 
     // TODO: 
    } 
    @objc func dismissController(_ sender:AnyObject) { 
     // TODO: 
    } 
    @objc func showNotification(_ sender:AnyObject) { 
     // TODO: 
    } 
} 
İlgili konular