Bram'in
Bram'in

Reputation: 638

How to add an observer for a changing height?

I've a textfield zone which is supposed to have a flexible height, growing along number of lines you have written.

I would like to listen to it's height's change and then when a new line will be create this listener will say "Hi the height has changed !".

Initial Height

---------- Initial Height ----------

Height has changed !

---------- Height has changed !!! ----------

I can't find out a proper way to do this, because addObserver in swift require a NotificationIdentifier like keyboardWillShow and here I don't have one like heightWillChange.

How can I call a function when the height changed ?

Upvotes: 1

Views: 2053

Answers (3)

Vova Kalinichenko
Vova Kalinichenko

Reputation: 149

extension MyThing: UITextViewDelegate {
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        guard let oldText = textView.text else {
            return true
        }
        let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)

        let size = CGSize(width: textView.bounds.width, height: CGFloat.greatestFiniteMagnitude)
        let font = textView.font!

        let oldTextRect = newText.boundingRect(with: size,
                                               options: .usesLineFragmentOrigin,
                                               attributes: [.font : font],
                                               context: nil)
        let newTextRect = oldText.boundingRect(with: size,
                                               options: .usesLineFragmentOrigin,
                                               attributes: [.font : font],
                                               context: nil)
        if oldTextRect != newTextRect {
            print("Text height changed")
        } else {
            print("Text height didnt change :(")
        }
        return true
    }
}

Upvotes: 0

beyowulf
beyowulf

Reputation: 15331

You can use KVO. If you're doing this from a view controller you can add observing in viewDidLoad. For example:

    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))

        self.textField.addObserver(self, forKeyPath: "frame", options: .New, context: nil)
    }

Then respond in:

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if keyPath == "frame" && object === self.textField
        {
            print(self.textField.frame)
        }
    }

Then remove observing when your view controller is deinited:

deinit {
    self.textField.removeObserver(self, forKeyPath: "frame")
}

Upvotes: 1

Yury
Yury

Reputation: 6114

Use delegate method of your UITextView

var textViewHeight: CGFloat = 0

func textViewDidChange(textView: UITextView)
{
    let newTextViewHeight = textView.frame.size.height
    if textViewHeight != newTextViewHeight
    {
        print("---------- Height has changed !!! ----------")
    }
    textViewHeight = newTextViewHeight
}

Upvotes: 1

Related Questions