在Swift中使用KVO观察contentSize(CGSize)

10

我正在尝试这样观察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'

需要帮助,谢谢!

4个回答

14

使用Swift 4,您可以将change字典针对键NSKeyValueChangeKey.newKey的结果转换为类型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)
    }

}

1
关于Swift 4代码:当滚动视图滚动时,是否应该调用此代码?每次我滚动时,都会获得多个连续输出,并且内容大小相同。我认为只有当实际内容大小改变时才应该触发这个代码。 - hidden-username
... observe(\UITextView.contentSize ... 中,反斜杠“\”有什么作用? - shallowThought

3

你使用的是iOS吗?因为我也在使用,我遇到了同样的问题并且产生了同样的疑问:为什么要使用NSSize?也许这只是xcode终端在跟我们开玩笑。

无论如何,你可以将其转换成NSValue,然后就能使用CGSizeValue

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

1

有一种更简单且可能更快的替代方法。

您可以子类化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
    }

}

0

看看这个示例代码:

if context == ApprovalObservingContext{
        if let theChange = change as? [NSString: Bool]{

            var newContentSize = change[NSKeyValueChangeNewKey]?.CGSizeValue()
        }
    }

这没有报错。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接