Sco*_* OB 12 macos cocoa nstextfield autolayout
一旦用户输入足够的文本来溢出控件的宽度,我试图让我的NSTextField的高度增长(就像在iChat或Adium中一样)(如本文所述)
我已经接受了接受的答案,但我似乎无法让它发挥作用.我已将我的尝试上传到http://scottyob.com/pub/autoGrowingExample.zip
理想情况下,当文本增长时,包含的窗口应随之增长,但我正在尝试婴儿步骤.
Dou*_*iot 18
阅读Apple文档通常很有帮助.Apple已经设计了所有这些文本布局的东西,足以处理各种复杂的边缘情况,这有时非常有用,有时甚至没有.
首先,我将文本字段设置为在分词上换行,所以我们实际上得到了多行.(您的示例代码甚至有一个if语句,因此在关闭包装时它根本没有做任何事情).
这个的诀窍是要注意,当正在编辑文本时,它是由"字段编辑器"打印的 - 一个重量级的NSTextView对象,由a 拥有NSWindow,NSTextField被当前的"第一响应者"(被选中)重用.它NSTextView有一个NSTextContainer(文本去的矩形),它有一个NSLayoutManager布局文本.我们可以向布局管理器询问它想要消耗多少空间,以获得文本字段的新高度.
另一个技巧是覆盖NSText委托方法,- (void)textDidChange:(NSNotification *)notification以便在文本更改时使内在内容大小无效(因此,当您通过按返回提交更改时,它不会等待更新).
我没有cellSizeForBounds像你最初建议的那样使用的原因是我无法解决你的问题 - 即使在使单元的内在内容大小无效时,cellSizeForBounds:仍继续返回旧的大小.
在GitHub上找到示例项目.
@interface TSTTextGrowth()
{
BOOL _hasLastIntrinsicSize;
BOOL _isEditing;
NSSize _lastIntrinsicSize;
}
@end
@implementation TSTTextGrowth
- (void)textDidBeginEditing:(NSNotification *)notification
{
[super textDidBeginEditing:notification];
_isEditing = YES;
}
- (void)textDidEndEditing:(NSNotification *)notification
{
[super textDidEndEditing:notification];
_isEditing = NO;
}
- (void)textDidChange:(NSNotification *)notification
{
[super textDidChange:notification];
[self invalidateIntrinsicContentSize];
}
-(NSSize)intrinsicContentSize
{
NSSize intrinsicSize = _lastIntrinsicSize;
// 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 || !_hasLastIntrinsicSize)
{
intrinsicSize = [super intrinsicContentSize];
// If we’re being edited, get the shared NSTextView field editor, so we can get more info
NSText *fieldEditor = [self.window fieldEditor:NO forObject:self];
if([fieldEditor isKindOfClass:[NSTextView class]])
{
NSTextView *textView = (NSTextView *)fieldEditor;
NSRect usedRect = [textView.textContainer.layoutManager usedRectForTextContainer:textView.textContainer];
usedRect.size.height += 5.0; // 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
intrinsicSize.height = usedRect.size.height;
}
_lastIntrinsicSize = intrinsicSize;
_hasLastIntrinsicSize = YES;
}
return intrinsicSize;
}
@end
Run Code Online (Sandbox Code Playgroud)
作为最后一点,我自己从未真正使用过自动布局 - 这些演示看起来很神奇,但每当我亲自尝试时,我都无法让它工作得非常正确而且会让事情变得更复杂.然而,在这种情况下,我认为它实际上确实节省了大量的工作 - 没有它,-intrinsicContentSize就不存在了,你可能必须自己设置框架,计算新的原点以及新的尺寸(不是困难,但只是更多的代码).
DouglasHeriot的解决方案仅适用于固定宽度的文本字段.在我的应用程序中,我有文本字段,我想在水平和垂直方向上增长.因此我修改了解决方案如下:
AutosizingTextField.h
@interface AutosizingTextField : NSTextField {
BOOL isEditing;
}
@end
Run Code Online (Sandbox Code Playgroud)
AutosizingTextField.m
@implementation AutosizingTextField
- (void)textDidBeginEditing:(NSNotification *)notification
{
[super textDidBeginEditing:notification];
isEditing = YES;
}
- (void)textDidEndEditing:(NSNotification *)notification
{
[super textDidEndEditing:notification];
isEditing = NO;
}
- (void)textDidChange:(NSNotification *)notification
{
[super textDidChange:notification];
[self invalidateIntrinsicContentSize];
}
-(NSSize)intrinsicContentSize
{
if(isEditing)
{
NSText *fieldEditor = [self.window fieldEditor:NO forObject:self];
if(fieldEditor)
{
NSTextFieldCell *cellCopy = [self.cell copy];
cellCopy.stringValue = fieldEditor.string;
return [cellCopy cellSize];
}
}
return [self.cell cellSize];
}
@end
Run Code Online (Sandbox Code Playgroud)
还有一个小问题:当键入空格时,文本会向左跳跃一点.但是,这在我的应用程序中不是问题,因为在大多数情况下文本字段不应包含空格.
小智 5
DouglasHeriot 的解决方案对我很有用。
这是 Swift 4 上的相同代码
class GrowingTextField: NSTextField {
var editing = false
var lastIntrinsicSize = NSSize.zero
var hasLastIntrinsicSize = false
override func textDidBeginEditing(_ notification: Notification) {
super.textDidBeginEditing(notification)
editing = true
}
override func textDidEndEditing(_ notification: Notification) {
super.textDidEndEditing(notification)
editing = false
}
override func textDidChange(_ notification: Notification) {
super.textDidChange(notification)
invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: NSSize {
get {
var intrinsicSize = lastIntrinsicSize
if editing || !hasLastIntrinsicSize {
intrinsicSize = super.intrinsicContentSize
// If we’re being edited, get the shared NSTextView field editor, so we can get more info
if let textView = self.window?.fieldEditor(false, for: self) as? NSTextView, let textContainer = textView.textContainer, var usedRect = textView.textContainer?.layoutManager?.usedRect(for: textContainer) {
usedRect.size.height += 5.0 // 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
intrinsicSize.height = usedRect.size.height
}
lastIntrinsicSize = intrinsicSize
hasLastIntrinsicSize = true
}
return intrinsicSize
}
}
}
Run Code Online (Sandbox Code Playgroud)
当设置文本字段的字符串值以及通过自动布局调整其大小时,此解决方案也适用。它只是在需要时使用属性文本属性来计算内在内容大小。
class AutoGrowingTextField: NSTextField {
var maximumHeight: CGFloat = 100
override var intrinsicContentSize: NSSize {
let height = attributedStringValue.boundingRect(
with: NSSize(width: bounds.width - 8, height: maximumHeight),
options: [NSString.DrawingOptions.usesLineFragmentOrigin]
).height + 5
return NSSize(width: NSView.noIntrinsicMetric, height: height)
}
override func textDidChange(_ notification: Notification) {
super.textDidChange(notification)
invalidateIntrinsicContentSize()
}
override func layout() {
super.layout()
invalidateIntrinsicContentSize()
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6185 次 |
| 最近记录: |