【问题标题】:Shared UI function between view controllers视图控制器之间共享 UI 功能
【发布时间】:2016-09-30 01:56:13
【问题描述】:

我有一些与 UI 相关的功能,例如显示警告弹出窗口,在屏幕中间显示活动指示器,或在屏幕上显示带有自定义消息的动画 UIView。
我想在多个 viewControllers(VC1 , 和 VC2 在这种情况下),所以我不重复自己。
最初,我有以下代码,这两个 VC 都继承自一个负责这些功能的 BaseVC。
VC1 是一个嵌入了 tablelView 的 UIViewController,VC2 是一个嵌入了 collectionView 的 UIViewController。

class VC1: BaseVC {
    func viewDidAppear(animated: Bool) {
        activityIndicatorBegin()
    }

    func btnPressed() {
        activityIndicatorEnd()
    }
}

class VC2: BaseVC {
    func viewDidAppear(animated: Bool) {
        activityIndicatorBegin()
    }

    func btnPressed() {
        activityIndicatorEnd()
    }
}

class BaseVC: UIViewController {

    var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
    var isCustomViewOnScreen = false

    func activityIndicatorBegin() {
        if activityIndicator.isAnimating() == false {
            activityIndicator = UIActivityIndicatorView(frame: CGRectMake(0,0,20,20))
            activityIndicator.center = view.center
            activityIndicator.hidesWhenStopped = true
            activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
            activityIndicator.color = UIColor.blackColor()
            view.addSubview(activityIndicator)
            activityIndicator.startAnimating()
        }
    }

    func activityIndicatorEnd() {
        if activityIndicator.isAnimating() == true {
            activityIndicator.stopAnimating()
            activityIndicator.removeFromSuperview()
        }
    }

    func animateACustomViewOnScreen() {
        if isCustomViewOnScreen == false {
            // Some animation code 
        }
    }

    func removeCustomView() {
        if isCustomViewOnScreen == true {
            // Some removal code
        }
    }
}

但是,由于某些原因,我决定将 VC1 直接用于 UITableViewController 和来自 UICollectionViewController 的 VC2。
这意味着它们不再可以从属于 UIViewController 类的 BaseVC 中获取。

我怎样才能使两个 VC 仍然可以达到这些功能?

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    答案是Protocol Extensions。您将BaseVC 定义为协议,然后通过添加将在整个实现它的类中使用的共享逻辑来扩展它:

    (在下面的例子中,BaseVC 被重命名为ActivityIndicatorDisplaying。)

    protocol ActivityIndicatorDisplaying {
    
      var activityIndicator: UIActivityIndicatorView { get set }
      var showsCustomView: Bool { get }
    
      func showActivityIndicator()
      func dismissActivityIndicator()
    }
    
    extension ActivityIndicatorDisplaying where Self: UIViewController {
    
      func showActivityIndicator() {
        if activityIndicator.isAnimating() { return }
    
        activityIndicator.center = CGPointMake(view.bounds.width / 2, view.bounds.height / 2)
        activityIndicator.hidesWhenStopped = true
        activityIndicator.activityIndicatorViewStyle = .WhiteLarge
        activityIndicator.color = UIColor.blackColor()
        view.addSubview(activityIndicator)
        activityIndicator.startAnimating()
      }
    
      func dismissActivityIndicator() {
        activityIndicator.stopAnimating()
        activityIndicator.removeFromSuperview()
      }
    
      func animateACustomViewOnScreen() {
        if !showsCustomView {
          // Some animation code
        }
      }
    
      func removeCustomView() {
        if showsCustomView {
          // Some removal code
        }
      }
    }
    
    class VC1: UITableViewController, ActivityIndicatorDisplaying {
    
      var activityIndicator = UIActivityIndicatorView()
      var showsCustomView: Bool = false
    
      override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
    
        showActivityIndicator()
      }
    
      func btnPressed() {
        dismissActivityIndicator()
      }
    }
    
    class VC2: UICollectionViewController, ActivityIndicatorDisplaying {
    
      var activityIndicator = UIActivityIndicatorView()
      var showsCustomView: Bool = true
    
      ...
    }
    

    【讨论】:

    • 很好的答案,但extension ActivityIndicatorDisplaying where Self: UIViewController 如果您显示UIView 仍然有效?
    • 不,因为 .addSubview 在视图控制器的 .view 属性上被调用,所以它不起作用。如果您希望它同时与 UIView 和 UIViewController 一起使用,那么您应该删除 where Self: UIViewController 并在协议中定义另一个属性,例如:var view: UIView { get }
    • 为什么这个解决方案比 Jason 的投票有更多的投票?他的方式并没有在所有 VC 中引入额外的标志
    【解决方案2】:

    为什么不继承 UIActivityViewController 本身呢? 它会更合乎逻辑和更清晰。

    class VC1: UIViewController {
        var customActivityIndicatorView: CustomActivityIndicatorView? = nil
    
        func viewDidAppear(animated: Bool) {
            if let view = view {
                customActivityIndicatorView = CustomActivityIndicatorView(parentView: view)
            }
        }
    
        func btnPressed() {
            customActivityIndicatorView?.end()
        }
    }
    
    class VC2: UITableViewController {
        var customActivityIndicatorView: CustomActivityIndicatorView? = nil
    
        func viewDidAppear(animated: Bool) {
            if let view = view {
                customActivityIndicatorView = CustomActivityIndicatorView(parentView: view)
            }
        }
    
        func btnPressed() {
            customActivityIndicatorView?.end()
        }
    }
    
    class CustomActivityIndicatorView: UIActivityIndicatorView {
        var isCustomViewOnScreen = false
    
        convenience init?(parentView: UIView) {
            if isAnimating == false {
                self.init(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
                center = parentView.center
                hidesWhenStopped = true
                activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
                color = UIColor.black
                parentView.addSubview(self)
                startAnimating()
            } else {
                return nil
            }
        }
    
        func end() {
            if isAnimating == true {
                stopAnimating()
                removeFromSuperview()
            }
        }
    
        func animateACustomViewOnScreen() {
            if isCustomViewOnScreen == false {
                // Some animation code
            }
        }
    
        func removeCustomView() {
            if isCustomViewOnScreen == true {
                // Some removal code
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-23
      • 2017-06-06
      • 2013-06-19
      • 2019-06-05
      • 1970-01-01
      相关资源
      最近更新 更多