【问题标题】:observing contentSize (CGSize) with KVO in swift在 swift 中使用 KVO 观察 contentSize (CGSize)
【发布时间】:2015-07-15 04:14:05
【问题描述】:

我正在尝试像这样观察collectionView.contentSize

func startObserveCollectionView() {
    collectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old.union(NSKeyValueObservingOptions.New), context: &SearchDasboardLabelContext)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &SearchDasboardLabelContext {       
        if object === collectionView && keyPath! == "contentSize" {
            print(change)               
        }
    }
}

在 xcode 终端中,我得到了 NSSize 而不是 CGSize,如下所示:

Optional(["old": NSSize: {320, 0}, "new": NSSize: {375, 39.5}, "kind": 1])

在objective-c中我使用了CGSizeValue方法

CGSize newContentSize = [[change objectForKey:NSKeyValueChangeNewKey] CGSizeValue];

swift中有没有类似CGSizeValue的方法

我在 swift var newContentSize = change[NSKeyValueChangeNewKey]?.CGSizeValue() 中尝试过,但出错了

找不到成员“CGSizeValue”

需要帮助吗?谢谢

【问题讨论】:

    标签: xcode swift key-value-observing


    【解决方案1】:

    使用 Swift 4,您可以将键 NSKeyValueChangeKey.newKeychange 字典的结果转换为 CGSize 类型:

    if let size = change?[NSKeyValueChangeKey.newKey] as? CGSize {
        /* ... */
    }
    

    以下UIViewController 实现展示了如何设置KVO 堆栈以观察任何UIScrollView 子类(例如UITextView)的contentSize 属性的变化:

    import UIKit
    
    private var myContext = 0
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var textView: UITextView!
    
        /* ... */
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            textView.addObserver(self, forKeyPath: #keyPath(UITextView.contentSize), options: [NSKeyValueObservingOptions.new], context: &myContext)
        }
    
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            if context == &myContext,
                keyPath == #keyPath(UITextView.contentSize),
                let contentSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
                print("contentSize:", contentSize)
            }
        }
    
        deinit {
            textView.removeObserver(self, forKeyPath: #keyPath(UITextView.contentSize))
        }
    
    }
    

    请注意,对于 Swift 4,作为 addObserver(_:, forKeyPath:, options:, context:)observeValue(forKeyPath:, of:, change:, context:) 的替代方案,您可以使用 observe(_:, options:, changeHandler:) 来跟踪您的 UIScrollView 子类 contentSize 属性更改:

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var textView: UITextView!
        var observer: NSKeyValueObservation?
    
        /* ... */
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let handler = { (textView: UITextView, change: NSKeyValueObservedChange<CGSize>) in
                if let contentSize = change.newValue {
                    print("contentSize:", contentSize)
                }
            }
            observer = textView.observe(\UITextView.contentSize, options: [NSKeyValueObservingOptions.new], changeHandler: handler)
        }
    
    }
    

    【讨论】:

    • 关于 Swift 4 代码:这应该在滚动视图滚动时调用吗?每次滚动时,我都会获得具有相同 contentSize 的多个连续输出。我认为这应该只在实际 contentSize 发生变化时触发
    • ... observe(\UITextView.contentSize ...中的“\”是干什么用的?
    • 感谢您的笔记!
    【解决方案2】:

    你在 iOS 上吗?因为我是,所以我做了同样的事情并得出了同样的问题;为什么NSSize?也许这只是 xcode 终端在欺骗我们。

    无论如何,您可以将其转换为NSValue,然后您就可以使用CGSizeValue

    if let zeChange = change as? [NSString: NSValue] {
        let oldSize = zeChange[NSKeyValueChangeOldKey]?.CGSizeValue()
        let newSize = zeChange[NSKeyValueChangeNewKey]?.CGSizeValue()
    }
    

    【讨论】:

      【解决方案3】:

      有一个更简单且可以说更快捷的替代方案。

      您可以继承UICollectionViewLayout(或其任何子类,如UICollectionViewFlowLayout)并覆盖计算属性collectionViewContentSize。通过调用super,您将获得您的集合的 contentSize 并能够将该值委托回您的代码。

      所以你会有这样的东西:

      protocol FlowLayoutDelegate: class {
          func collectionView(_ collectionView: UICollectionView?, didChange contentSize: CGSize)
      }
      
      class FlowLayout: UICollectionViewFlowLayout {
      
          weak var delegate: FlowLayoutDelegate?
      
          override var collectionViewContentSize: CGSize {
              let contentSize = super.collectionViewContentSize
              delegate?.collectionView(collectionView, didChange: contentSize)
              return contentSize
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        查看此示例代码:

        if context == ApprovalObservingContext{
                if let theChange = change as? [NSString: Bool]{
        
                    var newContentSize = change[NSKeyValueChangeNewKey]?.CGSizeValue()
                }
            }
        

        这没有给出任何错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-02-02
          • 1970-01-01
          • 1970-01-01
          • 2014-07-28
          • 1970-01-01
          • 2014-08-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多