Last active
January 18, 2022 13:02
-
-
Save takuoka/ddc136832a87a0fd2f9a0a6d4cf754ea to your computer and use it in GitHub Desktop.
Example of an NSTextField that expands its height automatically. https://github.com/DouglasHeriot/AutoGrowingNSTextField
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
// https://github.com/DouglasHeriot/AutoGrowingNSTextField | |
// for AutoLayout | |
class AutoGrowingTextField: NSTextField { | |
var minHeight: CGFloat? = 100 | |
let bottomSpace: CGFloat = 5 | |
// magic number! (the field editor TextView is offset within the NSTextField. It’s easy to get the space above (it’s origin), but it’s difficult to get the default spacing for the bottom, as we may be changing the height | |
var heightLimit: CGFloat? | |
var lastSize: NSSize? | |
var isEditing = false | |
override func textDidBeginEditing(notification: NSNotification) { | |
super.textDidBeginEditing(notification) | |
isEditing = true | |
} | |
override func textDidEndEditing(notification: NSNotification) { | |
super.textDidEndEditing(notification) | |
isEditing = false | |
} | |
override func textDidChange(notification: NSNotification) { | |
super.textDidChange(notification) | |
self.invalidateIntrinsicContentSize() | |
} | |
override var intrinsicContentSize: NSSize { | |
var minSize: NSSize { | |
var size = super.intrinsicContentSize | |
size.height = minHeight ?? 0 | |
return size | |
} | |
// Only update the size if we’re editing the text, or if we’ve not set it yet | |
// If we try and update it while another text field is selected, it may shrink back down to only the size of one line (for some reason?) | |
if isEditing || lastSize == nil { | |
guard let | |
// If we’re being edited, get the shared NSTextView field editor, so we can get more info | |
textView = self.window?.fieldEditor(false, forObject: self) as? NSTextView, | |
container = textView.textContainer, | |
newHeight = container.layoutManager?.usedRectForTextContainer(container).height | |
else { | |
return lastSize ?? minSize | |
} | |
var newSize = super.intrinsicContentSize | |
newSize.height = newHeight + bottomSpace | |
if let | |
heightLimit = heightLimit, | |
lastSize = lastSize | |
where newSize.height > heightLimit { | |
newSize = lastSize | |
} | |
if let | |
minHeight = minHeight | |
where newSize.height < minHeight { | |
newSize.height = minHeight | |
} | |
lastSize = newSize | |
return newSize | |
} | |
else { | |
return lastSize ?? minSize | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can you please license this in a way where a GPL v3 app can use it? (also cc @DouglasHeriot). I'd love to use this but I don't want to just copy it unless you are fine with that.