xcode 使用 KVO 快速观察 contentSize (CGSize)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31421387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 07:28:33  来源:igfitidea点击:

observing contentSize (CGSize) with KVO in swift

xcodeswiftkey-value-observing

提问by Dennis Farandy

I'm trying to observering collectionView.contentSizelike this :

我正在尝试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)               
        }
    }
}

and in xcode terminal I got a NSSizenot CGSizelike this :

在 xcode 终端中,我得到了一个NSSizeCGSize这样的:

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

In objective-c I used method CGSizeValue

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

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

Is there any method like CGSizeValuein swift

有没有像CGSizeValueswift一样的方法

I have tried in swift var newContentSize = change[NSKeyValueChangeNewKey]?.CGSizeValue()but got error

我试过快速var newContentSize = change[NSKeyValueChangeNewKey]?.CGSizeValue()但出错

could not find member 'CGSizeValue'

找不到成员“CGSizeValue”

need help anyone? Thanks

需要帮助任何人?谢谢

采纳答案by Bluezen

Are you on iOS? Because I am, I did the same thing and arrived at the same question; why NSSize? Maybe that's just the xcode terminal playing a trick on us.

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

Anyway, you can cast it to an NSValuethen you will be able to use CGSizeValue:

无论如何,您可以将其转换为 anNSValue然后您将能够使用CGSizeValue

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

回答by Imanou Petit

With Swift 4, you can cast the result of the changedictionary for the key NSKeyValueChangeKey.newKeyas being of type CGSize:

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

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


The following UIViewControllerimplementation shows how to set a KVO stack in order to observe the changes of the contentSizeproperty of any UIScrollViewsubclass (e.g UITextView):

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

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

}


Note that with Swift 4, as an alternative to addObserver(_:, forKeyPath:, options:, context:)and observeValue(forKeyPath:, of:, change:, context:), you can use observe(_:, options:, changeHandler:)in order to track your UIScrollViewsubclass contentSizeproperty changes:

需要注意的是斯威夫特与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)
    }

}

回答by Dharmesh Kheni

Check out this example code:

查看此示例代码:

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

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

This is not giving any error.

这没有给出任何错误。

回答by Demosthese

There's a simpler and arguably swiftier alternative.

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

You can subclass UICollectionViewLayout(or any of its subclasses, like UICollectionViewFlowLayout) and override a computed property collectionViewContentSize. By calling superyou'll get the contentSize of your collection and be able to delegate this value back to your code.

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

So you'll have something like this:

所以你会有这样的事情:

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
    }

}