12

通常、プロジェクトにはの定義済みセットがあります。このセットはプロジェクトで使用でき、左側メニューボタンのように複数回使用して、表示されたビューコントローラを閉じる閉じるボタンでも異なって使用することができます。一般的なグローバルなエレガントな方法プロジェクトの任意のUIViewControllerにバーボタンアイテムを追加する

古典的なやり方は、必要に応じてこれらのボタンを追加することですが、これはコードの重複を導入し、私たちは皆それを避けたいと考えています。

アプローチを思い付くが、それははるかに完璧であることからのマイ:私のアプローチの限界がある

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

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

    、その後の使用

    拡張機能は、新しいView Controllerをインスタンス化する方法(たとえば、通知の場合)と、ビューコントローラは、それはあなただけUIViewController

  • ないエレガントを提示することを想定していたパラメータ

  • でinitedする必要があります。

私は、より柔軟に任意の考えを意図した結果を達成することができます指向プログラミング言語スウィフトとプロトコルとのより良い方法があることを確信していますか?

答えて

1

デフォルトのバーボタンの設定をしていますが、(UIViewControllerのサブクラスに)バーボタンのアクションの実装があるようです。あなたは1を言った: "拡張は、新しいビューコントローラをインスタンス化する方法を知る必要があります"と2番目のポイント2. "あなたは、UIViewControllerを提示したいと仮定しています"、拡張子がそのジョブをサブクラスそれらの行動と何をするべきかを知っています。ここではサンプル実装を行った:

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: 
    } 
} 
関連する問題